Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 39ad46...5c2c02 )
by Sebastian
16s
created

jquery.jplayer.js ➔ ... ➔ keyBindings   B

Complexity

Conditions 3
Paths 13

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
c 0
b 0
f 0
nc 13
nop 1
dl 0
loc 31
rs 8.8571
1
/*
2
 * jPlayer Plugin for jQuery JavaScript Library
3
 * http://www.jplayer.org
4
 *
5
 * Copyright (c) 2009 - 2014 Happyworm Ltd
6
 * Licensed under the MIT license.
7
 * http://opensource.org/licenses/MIT
8
 *
9
 * Author: Mark J Panaghiston
10
 * Version: 2.9.2
11
 * Date: 14th December 2014
12
 */
13
14
/* Support for Zepto 1.0 compiled with optional data module.
15
 * For AMD or NODE/CommonJS support, you will need to manually switch the related 2 lines in the code below.
16
 * Search terms: "jQuery Switch" and "Zepto Switch"
17
 */
18
19
(function (root, factory) {
20
	if (typeof define === 'function' && define.amd) {
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
21
		// AMD. Register as an anonymous module.
22
		define(['jquery'], factory); // jQuery Switch
23
		// define(['zepto'], factory); // Zepto Switch
24
	} else if (typeof exports === 'object') {
25
		// Node/CommonJS
26
		factory(require('jquery')); // jQuery Switch
27
		//factory(require('zepto')); // Zepto Switch
28
	} else {
29
		// Browser globals
30
		if(root.jQuery) { // Use jQuery if available
31
			factory(root.jQuery);
32
		} else { // Otherwise, use Zepto
33
			factory(root.Zepto);
34
		}
35
	}
36
}(this, function ($, undefined) {
37
38
	// Adapted from jquery.ui.widget.js (1.8.7): $.widget.bridge - Tweaked $.data(this,XYZ) to $(this).data(XYZ) for Zepto
39
	$.fn.jPlayer = function( options ) {
40
		var name = "jPlayer";
41
		var isMethodCall = typeof options === "string",
42
			args = Array.prototype.slice.call( arguments, 1 ),
43
			returnValue = this;
44
45
		// allow multiple hashes to be passed on init
46
		options = !isMethodCall && args.length ?
47
			$.extend.apply( null, [ true, options ].concat(args) ) :
48
			options;
49
50
		// prevent calls to internal methods
51
		if ( isMethodCall && options.charAt( 0 ) === "_" ) {
52
			return returnValue;
53
		}
54
55
		if ( isMethodCall ) {
56
			this.each(function() {
57
				var instance = $(this).data( name ),
58
					methodValue = instance && $.isFunction( instance[options] ) ?
59
						instance[ options ].apply( instance, args ) :
60
						instance;
61
				if ( methodValue !== instance && methodValue !== undefined ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if methodValue !== instance...thodValue !== undefined is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
62
					returnValue = methodValue;
63
					return false;
64
				}
65
			});
66
		} else {
67
			this.each(function() {
68
				var instance = $(this).data( name );
69
				if ( instance ) {
70
					// instance.option( options || {} )._init(); // Orig jquery.ui.widget.js code: Not recommend for jPlayer. ie., Applying new options to an existing instance (via the jPlayer constructor) and performing the _init(). The _init() is what concerns me. It would leave a lot of event handlers acting on jPlayer instance and the interface.
71
					instance.option( options || {} ); // The new constructor only changes the options. Changing options only has basic support atm.
72
				} else {
73
					$(this).data( name, new $.jPlayer( options, this ) );
74
				}
75
			});
76
		}
77
78
		return returnValue;
79
	};
80
81
	$.jPlayer = function( options, element ) {
82
		// allow instantiation without initializing for simple inheritance
83
		if ( arguments.length ) {
84
			this.element = $(element);
85
			this.options = $.extend(true, {},
86
				this.options,
87
				options
88
			);
89
			var self = this;
90
			this.element.bind( "remove.jPlayer", function() {
91
				self.destroy();
92
			});
93
			this._init();
94
		}
95
	};
96
	// End of: (Adapted from jquery.ui.widget.js (1.8.7))
97
98
	// Zepto is missing one of the animation methods.
99
	if(typeof $.fn.stop !== 'function') {
100
		$.fn.stop = function() {};
101
	}
102
103
	// Emulated HTML5 methods and properties
104
	$.jPlayer.emulateMethods = "load play pause";
105
	$.jPlayer.emulateStatus = "src readyState networkState currentTime duration paused ended playbackRate";
106
	$.jPlayer.emulateOptions = "muted volume";
107
108
	// Reserved event names generated by jPlayer that are not part of the HTML5 Media element spec
109
	$.jPlayer.reservedEvent = "ready flashreset resize repeat error warning";
110
111
	// Events generated by jPlayer
112
	$.jPlayer.event = {};
113
	$.each(
114
		[
115
			'ready',
116
			'setmedia', // Fires when the media is set
117
			'flashreset', // Similar to the ready event if the Flash solution is set to display:none and then shown again or if it's reloaded for another reason by the browser. For example, using CSS position:fixed on Firefox for the full screen feature.
118
			'resize', // Occurs when the size changes through a full/restore screen operation or if the size/sizeFull options are changed.
119
			'repeat', // Occurs when the repeat status changes. Usually through clicks on the repeat button of the interface.
120
			'click', // Occurs when the user clicks on one of the following: poster image, html video, flash video.
121
			'error', // Event error code in event.jPlayer.error.type. See $.jPlayer.error
122
			'warning', // Event warning code in event.jPlayer.warning.type. See $.jPlayer.warning
123
124
			// Other events match HTML5 spec.
125
			'loadstart',
126
			'progress',
127
			'suspend',
128
			'abort',
129
			'emptied',
130
			'stalled',
131
			'play',
132
			'pause',
133
			'loadedmetadata',
134
			'loadeddata',
135
			'waiting',
136
			'playing',
137
			'canplay',
138
			'canplaythrough',
139
			'seeking',
140
			'seeked',
141
			'timeupdate',
142
			'ended',
143
			'ratechange',
144
			'durationchange',
145
			'volumechange'
146
		],
147
		function() {
148
			$.jPlayer.event[ this ] = 'jPlayer_' + this;
149
		}
150
	);
151
152
	$.jPlayer.htmlEvent = [ // These HTML events are bubbled through to the jPlayer event, without any internal action.
153
		"loadstart",
154
		// "progress", // jPlayer uses internally before bubbling.
155
		// "suspend", // jPlayer uses internally before bubbling.
156
		"abort",
157
		// "error", // jPlayer uses internally before bubbling.
158
		"emptied",
159
		"stalled",
160
		// "play", // jPlayer uses internally before bubbling.
161
		// "pause", // jPlayer uses internally before bubbling.
162
		"loadedmetadata",
163
		// "loadeddata", // jPlayer uses internally before bubbling.
164
		// "waiting", // jPlayer uses internally before bubbling.
165
		// "playing", // jPlayer uses internally before bubbling.
166
		"canplay",
167
		"canplaythrough"
168
		// "seeking", // jPlayer uses internally before bubbling.
169
		// "seeked", // jPlayer uses internally before bubbling.
170
		// "timeupdate", // jPlayer uses internally before bubbling.
171
		// "ended", // jPlayer uses internally before bubbling.
172
		// "ratechange" // jPlayer uses internally before bubbling.
173
		// "durationchange" // jPlayer uses internally before bubbling.
174
		// "volumechange" // jPlayer uses internally before bubbling.
175
	];
176
177
	$.jPlayer.pause = function() {
178
		$.jPlayer.prototype.destroyRemoved();
179
		$.each($.jPlayer.prototype.instances, function(i, element) {
180
			if(element.data("jPlayer").status.srcSet) { // Check that media is set otherwise would cause error event.
181
				element.jPlayer("pause");
182
			}
183
		});
184
	};
185
186
	// Default for jPlayer option.timeFormat
187
	$.jPlayer.timeFormat = {
188
		showHour: false,
189
		showMin: true,
190
		showSec: true,
191
		padHour: false,
192
		padMin: true,
193
		padSec: true,
194
		sepHour: ":",
195
		sepMin: ":",
196
		sepSec: ""
197
	};
198
	var ConvertTime = function() {
199
		this.init();
200
	};
201
	ConvertTime.prototype = {
202
		init: function() {
203
			this.options = {
204
				timeFormat: $.jPlayer.timeFormat
205
			};
206
		},
207
		time: function(s) { // function used on jPlayer.prototype._convertTime to enable per instance options.
208
			s = (s && typeof s === 'number') ? s : 0;
209
210
			var myTime = new Date(s * 1000),
211
				hour = myTime.getUTCHours(),
212
				min = this.options.timeFormat.showHour ? myTime.getUTCMinutes() : myTime.getUTCMinutes() + hour * 60,
213
				sec = this.options.timeFormat.showMin ? myTime.getUTCSeconds() : myTime.getUTCSeconds() + min * 60,
214
				strHour = (this.options.timeFormat.padHour && hour < 10) ? "0" + hour : hour,
215
				strMin = (this.options.timeFormat.padMin && min < 10) ? "0" + min : min,
216
				strSec = (this.options.timeFormat.padSec && sec < 10) ? "0" + sec : sec,
217
				strTime = "";
218
219
			strTime += this.options.timeFormat.showHour ? strHour + this.options.timeFormat.sepHour : "";
220
			strTime += this.options.timeFormat.showMin ? strMin + this.options.timeFormat.sepMin : "";
221
			strTime += this.options.timeFormat.showSec ? strSec + this.options.timeFormat.sepSec : "";
222
223
			return strTime;
224
		}
225
	};
226
	var myConvertTime = new ConvertTime();
227
	$.jPlayer.convertTime = function(s) {
228
		return myConvertTime.time(s);
229
	};
230
231
	// Adapting jQuery 1.4.4 code for jQuery.browser. Required since jQuery 1.3.2 does not detect Chrome as webkit.
232
	$.jPlayer.uaBrowser = function( userAgent ) {
233
		var ua = userAgent.toLowerCase();
234
235
		// Useragent RegExp
236
		var rwebkit = /(webkit)[ \/]([\w.]+)/;
237
		var ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/;
238
		var rmsie = /(msie) ([\w.]+)/;
239
		var rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/;
240
241
		var match = rwebkit.exec( ua ) ||
242
			ropera.exec( ua ) ||
243
			rmsie.exec( ua ) ||
244
			ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
245
			[];
246
247
		return { browser: match[1] || "", version: match[2] || "0" };
248
	};
249
250
	// Platform sniffer for detecting mobile devices
251
	$.jPlayer.uaPlatform = function( userAgent ) {
252
		var ua = userAgent.toLowerCase();
253
254
		// Useragent RegExp
255
		var rplatform = /(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/;
256
		var rtablet = /(ipad|playbook)/;
257
		var randroid = /(android)/;
258
		var rmobile = /(mobile)/;
259
260
		var platform = rplatform.exec( ua ) || [];
261
		var tablet = rtablet.exec( ua ) ||
262
			!rmobile.exec( ua ) && randroid.exec( ua ) ||
263
			[];
264
265
		if(platform[1]) {
266
			platform[1] = platform[1].replace(/\s/g, "_"); // Change whitespace to underscore. Enables dot notation.
267
		}
268
269
		return { platform: platform[1] || "", tablet: tablet[1] || "" };
270
	};
271
272
	$.jPlayer.browser = {
273
	};
274
	$.jPlayer.platform = {
275
	};
276
277
	var browserMatch = $.jPlayer.uaBrowser(navigator.userAgent);
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
278
	if ( browserMatch.browser ) {
279
		$.jPlayer.browser[ browserMatch.browser ] = true;
280
		$.jPlayer.browser.version = browserMatch.version;
281
	}
282
	var platformMatch = $.jPlayer.uaPlatform(navigator.userAgent);
283
	if ( platformMatch.platform ) {
284
		$.jPlayer.platform[ platformMatch.platform ] = true;
285
		$.jPlayer.platform.mobile = !platformMatch.tablet;
286
		$.jPlayer.platform.tablet = !!platformMatch.tablet;
287
	}
288
289
	// Internet Explorer (IE) Browser Document Mode Sniffer. Based on code at:
290
	// http://msdn.microsoft.com/en-us/library/cc288325%28v=vs.85%29.aspx#GetMode
291
	$.jPlayer.getDocMode = function() {
292
		var docMode;
293
		if ($.jPlayer.browser.msie) {
294
			if (document.documentMode) { // IE8 or later
295
				docMode = document.documentMode;
296
			} else { // IE 5-7
297
				docMode = 5; // Assume quirks mode unless proven otherwise
298
				if (document.compatMode) {
299
					if (document.compatMode === "CSS1Compat") {
300
						docMode = 7; // standards mode
301
					}
302
				}
303
			}
304
		}
305
		return docMode;
0 ignored issues
show
Bug introduced by
The variable docMode does not seem to be initialized in case $.jPlayer.browser.msie on line 293 is false. Are you sure this can never be the case?
Loading history...
306
	};
307
	$.jPlayer.browser.documentMode = $.jPlayer.getDocMode();
308
309
	$.jPlayer.nativeFeatures = {
310
		init: function() {
311
312
			/* Fullscreen function naming influenced by W3C naming.
313
			 * No support for: Mozilla Proposal: https://wiki.mozilla.org/Gecko:FullScreenAPI
314
			 */
315
316
			var d = document,
317
				v = d.createElement('video'),
318
				spec = {
319
					// http://www.w3.org/TR/fullscreen/
320
					w3c: [
321
						'fullscreenEnabled',
322
						'fullscreenElement',
323
						'requestFullscreen',
324
						'exitFullscreen',
325
						'fullscreenchange',
326
						'fullscreenerror'
327
					],
328
					// https://developer.mozilla.org/en-US/docs/DOM/Using_fullscreen_mode
329
					moz: [
330
						'mozFullScreenEnabled',
331
						'mozFullScreenElement',
332
						'mozRequestFullScreen',
333
						'mozCancelFullScreen',
334
						'mozfullscreenchange',
335
						'mozfullscreenerror'
336
					],
337
					// http://developer.apple.com/library/safari/#documentation/WebKit/Reference/ElementClassRef/Element/Element.html
338
					// http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/DocumentAdditionsReference/DocumentAdditions/DocumentAdditions.html
339
					webkit: [
340
						'',
341
						'webkitCurrentFullScreenElement',
342
						'webkitRequestFullScreen',
343
						'webkitCancelFullScreen',
344
						'webkitfullscreenchange',
345
						''
346
					],
347
					// http://developer.apple.com/library/safari/#documentation/AudioVideo/Reference/HTMLVideoElementClassReference/HTMLVideoElement/HTMLVideoElement.html
348
					// https://developer.apple.com/library/safari/samplecode/HTML5VideoEventFlow/Listings/events_js.html#//apple_ref/doc/uid/DTS40010085-events_js-DontLinkElementID_5
349
					// Events: 'webkitbeginfullscreen' and 'webkitendfullscreen'
350
					webkitVideo: [
351
						'webkitSupportsFullscreen',
352
						'webkitDisplayingFullscreen',
353
						'webkitEnterFullscreen',
354
						'webkitExitFullscreen',
355
						'',
356
						''
357
					],
358
					ms: [
359
						'',
360
						'msFullscreenElement',
361
						'msRequestFullscreen',
362
						'msExitFullscreen',
363
						'MSFullscreenChange',
364
						'MSFullscreenError'
365
					]
366
				},
367
				specOrder = [
368
					'w3c',
369
					'moz',
370
					'webkit',
371
					'webkitVideo',
372
					'ms'
373
				],
374
				fs, i, il;
375
376
			this.fullscreen = fs = {
377
				support: {
378
					w3c: !!d[spec.w3c[0]],
379
					moz: !!d[spec.moz[0]],
380
					webkit: typeof d[spec.webkit[3]] === 'function',
381
					webkitVideo: typeof v[spec.webkitVideo[2]] === 'function',
382
					ms: typeof v[spec.ms[2]] === 'function'
383
				},
384
				used: {}
385
			};
386
387
			// Store the name of the spec being used and as a handy boolean.
388
			for(i = 0, il = specOrder.length; i < il; i++) {
389
				var n = specOrder[i];
390
				if(fs.support[n]) {
391
					fs.spec = n;
392
					fs.used[n] = true;
393
					break;
394
				}
395
			}
396
397
			if(fs.spec) {
398
				var s = spec[fs.spec];
399
				fs.api = {
400
					fullscreenEnabled: true,
401
					fullscreenElement: function(elem) {
402
						elem = elem ? elem : d; // Video element required for webkitVideo
403
						return elem[s[1]];
404
					},
405
					requestFullscreen: function(elem) {
406
						return elem[s[2]](); // Chrome and Opera want parameter (Element.ALLOW_KEYBOARD_INPUT) but Safari fails if flag used.
407
					},
408
					exitFullscreen: function(elem) {
409
						elem = elem ? elem : d; // Video element required for webkitVideo
410
						return elem[s[3]]();
411
					}
412
				};
413
				fs.event = {
414
					fullscreenchange: s[4],
415
					fullscreenerror: s[5]
416
				};
417
			} else {
418
				fs.api = {
419
					fullscreenEnabled: false,
420
					fullscreenElement: function() {
421
						return null;
422
					},
423
					requestFullscreen: function() {},
424
					exitFullscreen: function() {}
425
				};
426
				fs.event = {};
427
			}
428
		}
429
	};
430
	$.jPlayer.nativeFeatures.init();
431
432
	// The keyboard control system.
433
434
	// The current jPlayer instance in focus.
435
	$.jPlayer.focus = null;
436
437
	// The list of element node names to ignore with key controls.
438
	$.jPlayer.keyIgnoreElementNames = "A INPUT TEXTAREA SELECT BUTTON";
439
440
	// The function that deals with key presses.
441
	var keyBindings = function(event) {
442
		var f = $.jPlayer.focus,
443
			ignoreKey;
444
445
		// A jPlayer instance must be in focus. ie., keyEnabled and the last one played.
446
		if(f) {
447
			// What generated the key press?
448
			$.each( $.jPlayer.keyIgnoreElementNames.split(/\s+/g), function(i, name) {
449
				// The strings should already be uppercase.
450
				if(event.target.nodeName.toUpperCase() === name.toUpperCase()) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if event.target.nodeName.to... === name.toUpperCase() is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
451
					ignoreKey = true;
452
					return false; // exit each.
453
				}
454
			});
455
			if(!ignoreKey) {
456
				// See if the key pressed matches any of the bindings.
457
				$.each(f.options.keyBindings, function(action, binding) {
458
					// The binding could be a null when the default has been disabled. ie., 1st clause in if()
459
					if(
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if binding && $.isFunction(...ent.key === binding.key is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
460
						(binding && $.isFunction(binding.fn)) &&
461
						((typeof binding.key === 'number' && event.which === binding.key) ||
462
						(typeof binding.key === 'string' && event.key === binding.key))
463
					) {
464
						event.preventDefault(); // Key being used by jPlayer, so prevent default operation.
465
						binding.fn(f);
466
						return false; // exit each.
467
					}
468
				});
469
			}
470
		}
471
	};
472
473
	$.jPlayer.keys = function(en) {
474
		var event = "keydown.jPlayer";
475
		// Remove any binding, just in case enabled more than once.
476
		$(document.documentElement).unbind(event);
477
		if(en) {
478
			$(document.documentElement).bind(event, keyBindings);
479
		}
480
	};
481
482
	// Enable the global key control handler ready for any jPlayer instance with the keyEnabled option enabled.
483
	$.jPlayer.keys(true);
484
485
	$.jPlayer.prototype = {
486
		count: 0, // Static Variable: Change it via prototype.
487
		version: { // Static Object
488
			script: "2.9.2",
489
			needFlash: "2.9.0",
490
			flash: "unknown"
491
		},
492
		options: { // Instanced in $.jPlayer() constructor
493
			swfPath: "js", // Path to jquery.jplayer.swf. Can be relative, absolute or server root relative.
494
			solution: "html, flash", // Valid solutions: html, flash, aurora. Order defines priority. 1st is highest,
495
			supplied: "mp3", // Defines which formats jPlayer will try and support and the priority by the order. 1st is highest,
496
			auroraFormats: "wav", // List the aurora.js codecs being loaded externally. Its core supports "wav". Specify format in jPlayer context. EG., The aac.js codec gives the "m4a" format.
497
			preload: 'metadata',  // HTML5 Spec values: none, metadata, auto.
498
			volume: 0.8, // The volume. Number 0 to 1.
499
			muted: false,
500
			remainingDuration: false, // When true, the remaining time is shown in the duration GUI element.
501
			toggleDuration: false, // When true, clicks on the duration toggle between the duration and remaining display.
502
			captureDuration: true, // When true, clicks on the duration are captured and no longer propagate up the DOM.
503
			playbackRate: 1,
504
			defaultPlaybackRate: 1,
505
			minPlaybackRate: 0.5,
506
			maxPlaybackRate: 4,
507
			wmode: "opaque", // Valid wmode: window, transparent, opaque, direct, gpu. 
508
			backgroundColor: "#000000", // To define the jPlayer div and Flash background color.
509
			cssSelectorAncestor: "#jp_container_1",
510
			cssSelector: { // * denotes properties that should only be required when video media type required. _cssSelector() would require changes to enable splitting these into Audio and Video defaults.
511
				videoPlay: ".jp-video-play", // *
512
				play: ".jp-play",
513
				pause: ".jp-pause",
514
				stop: ".jp-stop",
515
				seekBar: ".jp-seek-bar",
516
				playBar: ".jp-play-bar",
517
				mute: ".jp-mute",
518
				unmute: ".jp-unmute",
519
				volumeBar: ".jp-volume-bar",
520
				volumeBarValue: ".jp-volume-bar-value",
521
				volumeMax: ".jp-volume-max",
522
				playbackRateBar: ".jp-playback-rate-bar",
523
				playbackRateBarValue: ".jp-playback-rate-bar-value",
524
				currentTime: ".jp-current-time",
525
				duration: ".jp-duration",
526
				title: ".jp-title",
527
				fullScreen: ".jp-full-screen", // *
528
				restoreScreen: ".jp-restore-screen", // *
529
				repeat: ".jp-repeat",
530
				repeatOff: ".jp-repeat-off",
531
				gui: ".jp-gui", // The interface used with autohide feature.
532
				noSolution: ".jp-no-solution" // For error feedback when jPlayer cannot find a solution.
533
			},
534
			stateClass: { // Classes added to the cssSelectorAncestor to indicate the state.
535
				playing: "jp-state-playing",
536
				seeking: "jp-state-seeking",
537
				muted: "jp-state-muted",
538
				looped: "jp-state-looped",
539
				fullScreen: "jp-state-full-screen",
540
				noVolume: "jp-state-no-volume"
541
			},
542
			useStateClassSkin: false, // A state class skin relies on the state classes to change the visual appearance. The single control toggles the effect, for example: play then pause, mute then unmute.
543
			autoBlur: true, // GUI control handlers will drop focus after clicks.
544
			smoothPlayBar: false, // Smooths the play bar transitions, which affects clicks and short media with big changes per second.
545
			fullScreen: false, // Native Full Screen
546
			fullWindow: false,
547
			autohide: {
548
				restored: false, // Controls the interface autohide feature.
549
				full: true, // Controls the interface autohide feature.
550
				fadeIn: 200, // Milliseconds. The period of the fadeIn anim.
551
				fadeOut: 600, // Milliseconds. The period of the fadeOut anim.
552
				hold: 1000 // Milliseconds. The period of the pause before autohide beings.
553
			},
554
			loop: false,
555
			repeat: function(event) { // The default jPlayer repeat event handler
556
				if(event.jPlayer.options.loop) {
557
					$(this).unbind(".jPlayerRepeat").bind($.jPlayer.event.ended + ".jPlayer.jPlayerRepeat", function() {
558
						$(this).jPlayer("play");
559
					});
560
				} else {
561
					$(this).unbind(".jPlayerRepeat");
562
				}
563
			},
564
			nativeVideoControls: {
565
				// Works well on standard browsers.
566
				// Phone and tablet browsers can have problems with the controls disappearing.
567
			},
568
			noFullWindow: {
569
				msie: /msie [0-6]\./,
570
				ipad: /ipad.*?os [0-4]\./,
571
				iphone: /iphone/,
572
				ipod: /ipod/,
573
				android_pad: /android [0-3]\.(?!.*?mobile)/,
574
				android_phone: /(?=.*android)(?!.*chrome)(?=.*mobile)/,
575
				blackberry: /blackberry/,
576
				windows_ce: /windows ce/,
577
				iemobile: /iemobile/,
578
				webos: /webos/
579
			},
580
			noVolume: {
581
				ipad: /ipad/,
582
				iphone: /iphone/,
583
				ipod: /ipod/,
584
				android_pad: /android(?!.*?mobile)/,
585
				android_phone: /android.*?mobile/,
586
				blackberry: /blackberry/,
587
				windows_ce: /windows ce/,
588
				iemobile: /iemobile/,
589
				webos: /webos/,
590
				playbook: /playbook/
591
			},
592
			timeFormat: {
593
				// Specific time format for this instance. The supported options are defined in $.jPlayer.timeFormat
594
				// For the undefined options we use the default from $.jPlayer.timeFormat
595
			},
596
			keyEnabled: false, // Enables keyboard controls.
597
			audioFullScreen: false, // Enables keyboard controls to enter full screen with audio media.
598
			keyBindings: { // The key control object, defining the key codes and the functions to execute.
599
				// The parameter, f = $.jPlayer.focus, will be checked truethy before attempting to call any of these functions.
600
				// Properties may be added to this object, in key/fn pairs, to enable other key controls. EG, for the playlist add-on.
601
				play: {
602
					key: 80, // p
603
					fn: function(f) {
604
						if(f.status.paused) {
605
							f.play();
606
						} else {
607
							f.pause();
608
						}
609
					}
610
				},
611
				fullScreen: {
612
					key: 70, // f
613
					fn: function(f) {
614
						if(f.status.video || f.options.audioFullScreen) {
615
							f._setOption("fullScreen", !f.options.fullScreen);
616
						}
617
					}
618
				},
619
				muted: {
620
					key: 77, // m
621
					fn: function(f) {
622
						f._muted(!f.options.muted);
623
					}
624
				},
625
				volumeUp: {
626
					key: 190, // .
627
					fn: function(f) {
628
						f.volume(f.options.volume + 0.1);
629
					}
630
				},
631
				volumeDown: {
632
					key: 188, // ,
633
					fn: function(f) {
634
						f.volume(f.options.volume - 0.1);
635
					}
636
				},
637
				loop: {
638
					key: 76, // l
639
					fn: function(f) {
640
						f._loop(!f.options.loop);
641
					}
642
				}
643
			},
644
			verticalVolume: false, // Calculate volume from the bottom of the volume bar. Default is from the left. Also volume affects either width or height.
645
			verticalPlaybackRate: false,
646
			globalVolume: false, // Set to make volume and muted changes affect all jPlayer instances with this option enabled
647
			idPrefix: "jp", // Prefix for the ids of html elements created by jPlayer. For flash, this must not include characters: . - + * / \
648
			noConflict: "jQuery",
649
			emulateHtml: false, // Emulates the HTML5 Media element on the jPlayer element.
650
			consoleAlerts: true, // Alerts are sent to the console.log() instead of alert().
651
			errorAlerts: false,
652
			warningAlerts: false
653
		},
654
		optionsAudio: {
655
			size: {
656
				width: "0px",
657
				height: "0px",
658
				cssClass: ""
659
			},
660
			sizeFull: {
661
				width: "0px",
662
				height: "0px",
663
				cssClass: ""
664
			}
665
		},
666
		optionsVideo: {
667
			size: {
668
				width: "480px",
669
				height: "270px",
670
				cssClass: "jp-video-270p"
671
			},
672
			sizeFull: {
673
				width: "100%",
674
				height: "100%",
675
				cssClass: "jp-video-full"
676
			}
677
		},
678
		instances: {}, // Static Object
679
		status: { // Instanced in _init()
680
			src: "",
681
			media: {},
682
			paused: true,
683
			format: {},
684
			formatType: "",
685
			waitForPlay: true, // Same as waitForLoad except in case where preloading.
686
			waitForLoad: true,
687
			srcSet: false,
688
			video: false, // True if playing a video
689
			seekPercent: 0,
690
			currentPercentRelative: 0,
691
			currentPercentAbsolute: 0,
692
			currentTime: 0,
693
			duration: 0,
694
			remaining: 0,
695
			videoWidth: 0, // Intrinsic width of the video in pixels.
696
			videoHeight: 0, // Intrinsic height of the video in pixels.
697
			readyState: 0,
698
			networkState: 0,
699
			playbackRate: 1, // Warning - Now both an option and a status property
700
			ended: 0
701
702
/*		Persistant status properties created dynamically at _init():
703
			width
704
			height
705
			cssClass
706
			nativeVideoControls
707
			noFullWindow
708
			noVolume
709
			playbackRateEnabled // Warning - Technically, we can have both Flash and HTML, so this might not be correct if the Flash is active. That is a niche case.
710
*/
711
		},
712
713
		internal: { // Instanced in _init()
714
			ready: false
715
			// instance: undefined
716
			// domNode: undefined
717
			// htmlDlyCmdId: undefined
718
			// autohideId: undefined
719
			// mouse: undefined
720
			// cmdsIgnored
721
		},
722
		solution: { // Static Object: Defines the solutions built in jPlayer.
723
			html: true,
724
			aurora: true,
725
			flash: true
726
		},
727
		// 'MPEG-4 support' : canPlayType('video/mp4; codecs="mp4v.20.8"')
728
		format: { // Static Object
729
			mp3: {
730
				codec: 'audio/mpeg',
731
				flashCanPlay: true,
732
				media: 'audio'
733
			},
734
			m4a: { // AAC / MP4
735
				codec: 'audio/mp4; codecs="mp4a.40.2"',
736
				flashCanPlay: true,
737
				media: 'audio'
738
			},
739
			m3u8a: { // AAC / MP4 / Apple HLS
740
				codec: 'application/vnd.apple.mpegurl; codecs="mp4a.40.2"',
741
				flashCanPlay: false,
742
				media: 'audio'
743
			},
744
			m3ua: { // M3U
745
				codec: 'audio/mpegurl',
746
				flashCanPlay: false,
747
				media: 'audio'
748
			},
749
			oga: { // OGG
750
				codec: 'audio/ogg; codecs="vorbis, opus"',
751
				flashCanPlay: false,
752
				media: 'audio'
753
			},
754
			flac: { // FLAC
755
				codec: 'audio/x-flac',
756
				flashCanPlay: false,
757
				media: 'audio'
758
			},
759
			wav: { // PCM
760
				codec: 'audio/wav; codecs="1"',
761
				flashCanPlay: false,
762
				media: 'audio'
763
			},
764
			webma: { // WEBM
765
				codec: 'audio/webm; codecs="vorbis"',
766
				flashCanPlay: false,
767
				media: 'audio'
768
			},
769
			fla: { // FLV / F4A
770
				codec: 'audio/x-flv',
771
				flashCanPlay: true,
772
				media: 'audio'
773
			},
774
			rtmpa: { // RTMP AUDIO
775
				codec: 'audio/rtmp; codecs="rtmp"',
776
				flashCanPlay: true,
777
				media: 'audio'
778
			},
779
			m4v: { // H.264 / MP4
780
				codec: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
781
				flashCanPlay: true,
782
				media: 'video'
783
			},
784
			m3u8v: { // H.264 / AAC / MP4 / Apple HLS
785
				codec: 'application/vnd.apple.mpegurl; codecs="avc1.42E01E, mp4a.40.2"',
786
				flashCanPlay: false,
787
				media: 'video'
788
			},
789
			m3uv: { // M3U
790
				codec: 'audio/mpegurl',
791
				flashCanPlay: false,
792
				media: 'video'
793
			},
794
			ogv: { // OGG
795
				codec: 'video/ogg; codecs="theora, vorbis"',
796
				flashCanPlay: false,
797
				media: 'video'
798
			},
799
			webmv: { // WEBM
800
				codec: 'video/webm; codecs="vorbis, vp8"',
801
				flashCanPlay: false,
802
				media: 'video'
803
			},
804
			flv: { // FLV / F4V
805
				codec: 'video/x-flv',
806
				flashCanPlay: true,
807
				media: 'video'
808
			},
809
			rtmpv: { // RTMP VIDEO
810
				codec: 'video/rtmp; codecs="rtmp"',
811
				flashCanPlay: true,
812
				media: 'video'
813
			}
814
		},
815
		_init: function() {
816
			var self = this;
817
			
818
			this.element.empty();
819
			
820
			this.status = $.extend({}, this.status); // Copy static to unique instance.
821
			this.internal = $.extend({}, this.internal); // Copy static to unique instance.
822
823
			// Initialize the time format
824
			this.options.timeFormat = $.extend({}, $.jPlayer.timeFormat, this.options.timeFormat);
825
826
			// On iOS, assume commands will be ignored before user initiates them.
827
			this.internal.cmdsIgnored = $.jPlayer.platform.ipad || $.jPlayer.platform.iphone || $.jPlayer.platform.ipod;
828
829
			this.internal.domNode = this.element.get(0);
830
831
			// Add key bindings focus to 1st jPlayer instanced with key control enabled.
832
			if(this.options.keyEnabled && !$.jPlayer.focus) {
833
				$.jPlayer.focus = this;
834
			}
835
836
			// A fix for Android where older (2.3) and even some 4.x devices fail to work when changing the *audio* SRC and then playing immediately.
837
			this.androidFix = {
838
				setMedia: false, // True when media set
839
				play: false, // True when a progress event will instruct the media to play
840
				pause: false, // True when a progress event will instruct the media to pause at a time.
841
				time: NaN // The play(time) parameter
842
			};
843
			if($.jPlayer.platform.android) {
844
				this.options.preload = this.options.preload !== 'auto' ? 'metadata' : 'auto'; // Default to metadata, but allow auto.
845
			}
846
847
			this.formats = []; // Array based on supplied string option. Order defines priority.
848
			this.solutions = []; // Array based on solution string option. Order defines priority.
849
			this.require = {}; // Which media types are required: video, audio.
850
			
851
			this.htmlElement = {}; // DOM elements created by jPlayer
852
			this.html = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
853
			this.html.audio = {};
854
			this.html.video = {};
855
			this.aurora = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
856
			this.aurora.formats = [];
857
			this.aurora.properties = [];
858
			this.flash = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
859
			
860
			this.css = {};
861
			this.css.cs = {}; // Holds the css selector strings
862
			this.css.jq = {}; // Holds jQuery selectors. ie., $(css.cs.method)
863
864
			this.ancestorJq = []; // Holds jQuery selector of cssSelectorAncestor. Init would use $() instead of [], but it is only 1.4+
865
866
			this.options.volume = this._limitValue(this.options.volume, 0, 1); // Limit volume value's bounds.
867
868
			// Create the formats array, with prority based on the order of the supplied formats string
869
			$.each(this.options.supplied.toLowerCase().split(","), function(index1, value1) {
870
				var format = value1.replace(/^\s+|\s+$/g, ""); //trim
871
				if(self.format[format]) { // Check format is valid.
872
					var dupFound = false;
873
					$.each(self.formats, function(index2, value2) { // Check for duplicates
874
						if(format === value2) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if format === value2 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
875
							dupFound = true;
876
							return false;
877
						}
878
					});
879
					if(!dupFound) {
880
						self.formats.push(format);
881
					}
882
				}
883
			});
884
885
			// Create the solutions array, with prority based on the order of the solution string
886
			$.each(this.options.solution.toLowerCase().split(","), function(index1, value1) {
887
				var solution = value1.replace(/^\s+|\s+$/g, ""); //trim
888
				if(self.solution[solution]) { // Check solution is valid.
889
					var dupFound = false;
890
					$.each(self.solutions, function(index2, value2) { // Check for duplicates
891
						if(solution === value2) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if solution === value2 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
892
							dupFound = true;
893
							return false;
894
						}
895
					});
896
					if(!dupFound) {
897
						self.solutions.push(solution);
898
					}
899
				}
900
			});
901
				
902
			// Create Aurora.js formats array
903
			$.each(this.options.auroraFormats.toLowerCase().split(","), function(index1, value1) {
904
				var format = value1.replace(/^\s+|\s+$/g, ""); //trim
905
				if(self.format[format]) { // Check format is valid.
906
					var dupFound = false;
907
					$.each(self.aurora.formats, function(index2, value2) { // Check for duplicates
908
						if(format === value2) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if format === value2 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
909
							dupFound = true;
910
							return false;
911
						}
912
					});
913
					if(!dupFound) {
914
						self.aurora.formats.push(format);
915
					}
916
				}
917
			});
918
919
			this.internal.instance = "jp_" + this.count;
920
			this.instances[this.internal.instance] = this.element;
921
922
			// Check the jPlayer div has an id and create one if required. Important for Flash to know the unique id for comms.
923
			if(!this.element.attr("id")) {
924
				this.element.attr("id", this.options.idPrefix + "_jplayer_" + this.count);
925
			}
926
927
			this.internal.self = $.extend({}, {
928
				id: this.element.attr("id"),
929
				jq: this.element
930
			});
931
			this.internal.audio = $.extend({}, {
932
				id: this.options.idPrefix + "_audio_" + this.count,
933
				jq: undefined
934
			});
935
			this.internal.video = $.extend({}, {
936
				id: this.options.idPrefix + "_video_" + this.count,
937
				jq: undefined
938
			});
939
			this.internal.flash = $.extend({}, {
940
				id: this.options.idPrefix + "_flash_" + this.count,
941
				jq: undefined,
942
				swf: this.options.swfPath + (this.options.swfPath.toLowerCase().slice(-4) !== ".swf" ? (this.options.swfPath && this.options.swfPath.slice(-1) !== "/" ? "/" : "") + "jquery.jplayer.swf" : "")
943
			});
944
			this.internal.poster = $.extend({}, {
945
				id: this.options.idPrefix + "_poster_" + this.count,
946
				jq: undefined
947
			});
948
949
			// Register listeners defined in the constructor
950
			$.each($.jPlayer.event, function(eventName,eventType) {
951
				if(self.options[eventName] !== undefined) {
952
					self.element.bind(eventType + ".jPlayer", self.options[eventName]); // With .jPlayer namespace.
953
					self.options[eventName] = undefined; // Destroy the handler pointer copy on the options. Reason, events can be added/removed in other ways so this could be obsolete and misleading.
954
				}
955
			});
956
957
			// Determine if we require solutions for audio, video or both media types.
958
			this.require.audio = false;
959
			this.require.video = false;
960
			$.each(this.formats, function(priority, format) {
961
				self.require[self.format[format].media] = true;
962
			});
963
964
			// Now required types are known, finish the options default settings.
965
			if(this.require.video) {
966
				this.options = $.extend(true, {},
967
					this.optionsVideo,
968
					this.options
969
				);
970
			} else {
971
				this.options = $.extend(true, {},
972
					this.optionsAudio,
973
					this.options
974
				);
975
			}
976
			this._setSize(); // update status and jPlayer element size
977
978
			// Determine the status for Blocklisted options.
979
			this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls);
980
			this.status.noFullWindow = this._uaBlocklist(this.options.noFullWindow);
981
			this.status.noVolume = this._uaBlocklist(this.options.noVolume);
982
983
			// Create event handlers if native fullscreen is supported
984
			if($.jPlayer.nativeFeatures.fullscreen.api.fullscreenEnabled) {
985
				this._fullscreenAddEventListeners();
986
			}
987
988
			// The native controls are only for video and are disabled when audio is also used.
989
			this._restrictNativeVideoControls();
990
991
			// Create the poster image.
992
			this.htmlElement.poster = document.createElement('img');
993
			this.htmlElement.poster.id = this.internal.poster.id;
994
			this.htmlElement.poster.onload = function() { // Note that this did not work on Firefox 3.6: poster.addEventListener("onload", function() {}, false); Did not investigate x-browser.
995
				if(!self.status.video || self.status.waitForPlay) {
996
					self.internal.poster.jq.show();
997
				}
998
			};
999
			this.element.append(this.htmlElement.poster);
1000
			this.internal.poster.jq = $("#" + this.internal.poster.id);
1001
			this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height});
1002
			this.internal.poster.jq.hide();
1003
			this.internal.poster.jq.bind("click.jPlayer", function() {
1004
				self._trigger($.jPlayer.event.click);
1005
			});
1006
			
1007
			// Generate the required media elements
1008
			this.html.audio.available = false;
1009
			if(this.require.audio) { // If a supplied format is audio
1010
				this.htmlElement.audio = document.createElement('audio');
1011
				this.htmlElement.audio.id = this.internal.audio.id;
1012
				this.html.audio.available = !!this.htmlElement.audio.canPlayType && this._testCanPlayType(this.htmlElement.audio); // Test is for IE9 on Win Server 2008.
1013
			}
1014
			this.html.video.available = false;
1015
			if(this.require.video) { // If a supplied format is video
1016
				this.htmlElement.video = document.createElement('video');
1017
				this.htmlElement.video.id = this.internal.video.id;
1018
				this.html.video.available = !!this.htmlElement.video.canPlayType && this._testCanPlayType(this.htmlElement.video); // Test is for IE9 on Win Server 2008.
1019
			}
1020
1021
			this.flash.available = this._checkForFlash(10.1);
1022
1023
			this.html.canPlay = {};
1024
			this.aurora.canPlay = {};
1025
			this.flash.canPlay = {};
1026
			$.each(this.formats, function(priority, format) {
1027
				self.html.canPlay[format] = self.html[self.format[format].media].available && "" !== self.htmlElement[self.format[format].media].canPlayType(self.format[format].codec);
1028
				self.aurora.canPlay[format] = ($.inArray(format, self.aurora.formats) > -1);
1029
				self.flash.canPlay[format] = self.format[format].flashCanPlay && self.flash.available;
1030
			});
1031
			this.html.desired = false;
1032
			this.aurora.desired = false;
1033
			this.flash.desired = false;
1034
			$.each(this.solutions, function(solutionPriority, solution) {
1035
				if(solutionPriority === 0) {
1036
					self[solution].desired = true;
1037
				} else {
1038
					var audioCanPlay = false;
1039
					var videoCanPlay = false;
1040
					$.each(self.formats, function(formatPriority, format) {
1041
						if(self[self.solutions[0]].canPlay[format]) { // The other solution can play
1042
							if(self.format[format].media === 'video') {
1043
								videoCanPlay = true;
1044
							} else {
1045
								audioCanPlay = true;
1046
							}
1047
						}
1048
					});
1049
					self[solution].desired = (self.require.audio && !audioCanPlay) || (self.require.video && !videoCanPlay);
1050
				}
1051
			});
1052
			// This is what jPlayer will support, based on solution and supplied.
1053
			this.html.support = {};
1054
			this.aurora.support = {};
1055
			this.flash.support = {};
1056
			$.each(this.formats, function(priority, format) {
1057
				self.html.support[format] = self.html.canPlay[format] && self.html.desired;
1058
				self.aurora.support[format] = self.aurora.canPlay[format] && self.aurora.desired;
1059
				self.flash.support[format] = self.flash.canPlay[format] && self.flash.desired;
1060
			});
1061
			// If jPlayer is supporting any format in a solution, then the solution is used.
1062
			this.html.used = false;
1063
			this.aurora.used = false;
1064
			this.flash.used = false;
1065
			$.each(this.solutions, function(solutionPriority, solution) {
1066
				$.each(self.formats, function(formatPriority, format) {
1067
					if(self[solution].support[format]) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if self.solution.support.format is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
1068
						self[solution].used = true;
1069
						return false;
1070
					}
1071
				});
1072
			});
1073
1074
			// Init solution active state and the event gates to false.
1075
			this._resetActive();
1076
			this._resetGate();
1077
1078
			// Set up the css selectors for the control and feedback entities.
1079
			this._cssSelectorAncestor(this.options.cssSelectorAncestor);
1080
			
1081
			// If neither html nor aurora nor flash are being used by this browser, then media playback is not possible. Trigger an error event.
1082
			if(!(this.html.used || this.aurora.used || this.flash.used)) {
1083
				this._error( {
1084
					type: $.jPlayer.error.NO_SOLUTION, 
1085
					context: "{solution:'" + this.options.solution + "', supplied:'" + this.options.supplied + "'}",
1086
					message: $.jPlayer.errorMsg.NO_SOLUTION,
1087
					hint: $.jPlayer.errorHint.NO_SOLUTION
1088
				});
1089
				if(this.css.jq.noSolution.length) {
1090
					this.css.jq.noSolution.show();
1091
				}
1092
			} else {
1093
				if(this.css.jq.noSolution.length) {
1094
					this.css.jq.noSolution.hide();
1095
				}
1096
			}
1097
1098
			// Add the flash solution if it is being used.
1099
			if(this.flash.used) {
1100
				var htmlObj,
1101
				flashVars = 'jQuery=' + encodeURI(this.options.noConflict) + '&id=' + encodeURI(this.internal.self.id) + '&vol=' + this.options.volume + '&muted=' + this.options.muted;
1102
1103
				// Code influenced by SWFObject 2.2: http://code.google.com/p/swfobject/
1104
				// Non IE browsers have an initial Flash size of 1 by 1 otherwise the wmode affected the Flash ready event. 
1105
1106
				if($.jPlayer.browser.msie && (Number($.jPlayer.browser.version) < 9 || $.jPlayer.browser.documentMode < 9)) {
1107
					var objStr = '<object id="' + this.internal.flash.id + '" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="0" height="0" tabindex="-1"></object>';
1108
1109
					var paramStr = [
1110
						'<param name="movie" value="' + this.internal.flash.swf + '" />',
1111
						'<param name="FlashVars" value="' + flashVars + '" />',
1112
						'<param name="allowScriptAccess" value="always" />',
1113
						'<param name="bgcolor" value="' + this.options.backgroundColor + '" />',
1114
						'<param name="wmode" value="' + this.options.wmode + '" />'
1115
					];
1116
1117
					htmlObj = document.createElement(objStr);
1118
					for(var i=0; i < paramStr.length; i++) {
1119
						htmlObj.appendChild(document.createElement(paramStr[i]));
1120
					}
1121
				} else {
1122
					var createParam = function(el, n, v) {
1123
						var p = document.createElement("param");
1124
						p.setAttribute("name", n);	
1125
						p.setAttribute("value", v);
1126
						el.appendChild(p);
1127
					};
1128
1129
					htmlObj = document.createElement("object");
1130
					htmlObj.setAttribute("id", this.internal.flash.id);
1131
					htmlObj.setAttribute("name", this.internal.flash.id);
1132
					htmlObj.setAttribute("data", this.internal.flash.swf);
1133
					htmlObj.setAttribute("type", "application/x-shockwave-flash");
1134
					htmlObj.setAttribute("width", "1"); // Non-zero
1135
					htmlObj.setAttribute("height", "1"); // Non-zero
1136
					htmlObj.setAttribute("tabindex", "-1");
1137
					createParam(htmlObj, "flashvars", flashVars);
1138
					createParam(htmlObj, "allowscriptaccess", "always");
1139
					createParam(htmlObj, "bgcolor", this.options.backgroundColor);
1140
					createParam(htmlObj, "wmode", this.options.wmode);
1141
				}
1142
1143
				this.element.append(htmlObj);
1144
				this.internal.flash.jq = $(htmlObj);
1145
			}
1146
1147
			// Setup playbackRate ability before using _addHtmlEventListeners()
1148
			if(this.html.used && !this.flash.used) { // If only HTML
1149
				// Using the audio element capabilities for playbackRate. ie., Assuming video element is the same.
1150
				this.status.playbackRateEnabled = this._testPlaybackRate('audio');
1151
			} else {
1152
				this.status.playbackRateEnabled = false;
1153
			}
1154
1155
			this._updatePlaybackRate();
1156
1157
			// Add the HTML solution if being used.
1158
			if(this.html.used) {
1159
1160
				// The HTML Audio handlers
1161
				if(this.html.audio.available) {
1162
					this._addHtmlEventListeners(this.htmlElement.audio, this.html.audio);
1163
					this.element.append(this.htmlElement.audio);
1164
					this.internal.audio.jq = $("#" + this.internal.audio.id);
1165
				}
1166
1167
				// The HTML Video handlers
1168
				if(this.html.video.available) {
1169
					this._addHtmlEventListeners(this.htmlElement.video, this.html.video);
1170
					this.element.append(this.htmlElement.video);
1171
					this.internal.video.jq = $("#" + this.internal.video.id);
1172
					if(this.status.nativeVideoControls) {
1173
						this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
1174
					} else {
1175
						this.internal.video.jq.css({'width':'0px', 'height':'0px'}); // Using size 0x0 since a .hide() causes issues in iOS
1176
					}
1177
					this.internal.video.jq.bind("click.jPlayer", function() {
1178
						self._trigger($.jPlayer.event.click);
1179
					});
1180
				}
1181
			}
1182
			
1183
			// Add the Aurora.js solution if being used.
1184
			if(this.aurora.used) {
1185
				// Aurora.js player need to be created for each media, see setMedia function.
1186
			}
1187
1188
			// Create the bridge that emulates the HTML Media element on the jPlayer DIV
1189
			if( this.options.emulateHtml ) {
1190
				this._emulateHtmlBridge();
1191
			}
1192
1193
			if((this.html.used || this.aurora.used) && !this.flash.used) { // If only HTML, then emulate flash ready() call after 100ms.
1194
				setTimeout( function() {
1195
					self.internal.ready = true;
1196
					self.version.flash = "n/a";
1197
					self._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option.
1198
					self._trigger($.jPlayer.event.ready);
1199
				}, 100);
1200
			}
1201
1202
			// Initialize the interface components with the options.
1203
			this._updateNativeVideoControls();
1204
			// The other controls are now setup in _cssSelectorAncestor()
1205
			if(this.css.jq.videoPlay.length) {
1206
				this.css.jq.videoPlay.hide();
1207
			}
1208
1209
			$.jPlayer.prototype.count++; // Change static variable via prototype.
1210
		},
1211
		destroy: function() {
1212
			// MJP: The background change remains. Would need to store the original to restore it correctly.
1213
			// MJP: The jPlayer element's size change remains.
1214
1215
			// Clear the media to reset the GUI and stop any downloads. Streams on some browsers had persited. (Chrome)
1216
			this.clearMedia();
1217
			// Remove the size/sizeFull cssClass from the cssSelectorAncestor
1218
			this._removeUiClass();
1219
			// Remove the times from the GUI
1220
			if(this.css.jq.currentTime.length) {
1221
				this.css.jq.currentTime.text("");
1222
			}
1223
			if(this.css.jq.duration.length) {
1224
				this.css.jq.duration.text("");
1225
			}
1226
			// Remove any bindings from the interface controls.
1227
			$.each(this.css.jq, function(fn, jq) {
1228
				// Check selector is valid before trying to execute method.
1229
				if(jq.length) {
1230
					jq.unbind(".jPlayer");
1231
				}
1232
			});
1233
			// Remove the click handlers for $.jPlayer.event.click
1234
			this.internal.poster.jq.unbind(".jPlayer");
1235
			if(this.internal.video.jq) {
1236
				this.internal.video.jq.unbind(".jPlayer");
1237
			}
1238
			// Remove the fullscreen event handlers
1239
			this._fullscreenRemoveEventListeners();
1240
			// Remove key bindings
1241
			if(this === $.jPlayer.focus) {
1242
				$.jPlayer.focus = null;
1243
			}
1244
			// Destroy the HTML bridge.
1245
			if(this.options.emulateHtml) {
1246
				this._destroyHtmlBridge();
1247
			}
1248
			this.element.removeData("jPlayer"); // Remove jPlayer data
1249
			this.element.unbind(".jPlayer"); // Remove all event handlers created by the jPlayer constructor
1250
			this.element.empty(); // Remove the inserted child elements
1251
			
1252
			delete this.instances[this.internal.instance]; // Clear the instance on the static instance object
1253
		},
1254
		destroyRemoved: function() { // Destroy any instances that have gone away.
1255
			var self = this;
1256
			$.each(this.instances, function(i, element) {
1257
				if(self.element !== element) { // Do not destroy this instance.
1258
					if(!element.data("jPlayer")) { // Check that element is a real jPlayer.
1259
						element.jPlayer("destroy");
1260
						delete self.instances[i];
1261
					}
1262
				}
1263
			});
1264
		},
1265
		enable: function() { // Plan to implement
1266
			// options.disabled = false
1267
		},
1268
		disable: function () { // Plan to implement
1269
			// options.disabled = true
1270
		},
1271
		_testCanPlayType: function(elem) {
1272
			// IE9 on Win Server 2008 did not implement canPlayType(), but it has the property.
1273
			try {
1274
				elem.canPlayType(this.format.mp3.codec); // The type is irrelevant.
1275
				return true;
1276
			} catch(err) {
1277
				return false;
1278
			}
1279
		},
1280
		_testPlaybackRate: function(type) {
1281
			// type: String 'audio' or 'video'
1282
			var el, rate = 0.5;
1283
			type = typeof type === 'string' ? type : 'audio';
1284
			el = document.createElement(type);
1285
			// Wrapping in a try/catch, just in case older HTML5 browsers throw and error.
1286
			try {
1287
				if('playbackRate' in el) {
1288
					el.playbackRate = rate;
1289
					return el.playbackRate === rate;
1290
				} else {
1291
					return false;
1292
				}
1293
			} catch(err) {
1294
				return false;
1295
			}
1296
		},
1297
		_uaBlocklist: function(list) {
1298
			// list : object with properties that are all regular expressions. Property names are irrelevant.
1299
			// Returns true if the user agent is matched in list.
1300
			var	ua = navigator.userAgent.toLowerCase(),
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1301
				block = false;
1302
1303
			$.each(list, function(p, re) {
1304
				if(re && re.test(ua)) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if re && re.test(ua) is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
1305
					block = true;
1306
					return false; // exit $.each.
1307
				}
1308
			});
1309
			return block;
1310
		},
1311
		_restrictNativeVideoControls: function() {
1312
			// Fallback to noFullWindow when nativeVideoControls is true and audio media is being used. Affects when both media types are used.
1313
			if(this.require.audio) {
1314
				if(this.status.nativeVideoControls) {
1315
					this.status.nativeVideoControls = false;
1316
					this.status.noFullWindow = true;
1317
				}
1318
			}
1319
		},
1320
		_updateNativeVideoControls: function() {
1321
			if(this.html.video.available && this.html.used) {
1322
				// Turn the HTML Video controls on/off
1323
				this.htmlElement.video.controls = this.status.nativeVideoControls;
1324
				// Show/hide the jPlayer GUI.
1325
				this._updateAutohide();
1326
				// For when option changed. The poster image is not updated, as it is dealt with in setMedia(). Acceptable degradation since seriously doubt these options will change on the fly. Can again review later.
1327
				if(this.status.nativeVideoControls && this.require.video) {
1328
					this.internal.poster.jq.hide();
1329
					this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
1330
				} else if(this.status.waitForPlay && this.status.video) {
1331
					this.internal.poster.jq.show();
1332
					this.internal.video.jq.css({'width': '0px', 'height': '0px'});
1333
				}
1334
			}
1335
		},
1336
		_addHtmlEventListeners: function(mediaElement, entity) {
1337
			var self = this;
1338
			mediaElement.preload = this.options.preload;
1339
			mediaElement.muted = this.options.muted;
1340
			mediaElement.volume = this.options.volume;
1341
1342
			if(this.status.playbackRateEnabled) {
1343
				mediaElement.defaultPlaybackRate = this.options.defaultPlaybackRate;
1344
				mediaElement.playbackRate = this.options.playbackRate;
1345
			}
1346
1347
			// Create the event listeners
1348
			// Only want the active entity to affect jPlayer and bubble events.
1349
			// Using entity.gate so that object is referenced and gate property always current
1350
			
1351
			mediaElement.addEventListener("progress", function() {
1352
				if(entity.gate) {
1353
					if(self.internal.cmdsIgnored && this.readyState > 0) { // Detect iOS executed the command
1354
						self.internal.cmdsIgnored = false;
1355
					}
1356
					self._getHtmlStatus(mediaElement);
1357
					self._updateInterface();
1358
					self._trigger($.jPlayer.event.progress);
1359
				}
1360
			}, false);
1361
			mediaElement.addEventListener("loadeddata", function() {
1362
				if(entity.gate) {
1363
					self.androidFix.setMedia = false; // Disable the fix after the first progress event.
1364
					if(self.androidFix.play) { // Play Android audio - performing the fix.
1365
						self.androidFix.play = false;
1366
						self.play(self.androidFix.time);
1367
					}
1368
					if(self.androidFix.pause) { // Pause Android audio at time - performing the fix.
1369
						self.androidFix.pause = false;
1370
						self.pause(self.androidFix.time);
1371
					}
1372
					self._trigger($.jPlayer.event.loadeddata);
1373
				}
1374
			}, false);
1375
			mediaElement.addEventListener("timeupdate", function() {
1376
				if(entity.gate) {
1377
					self._getHtmlStatus(mediaElement);
1378
					self._updateInterface();
1379
					self._trigger($.jPlayer.event.timeupdate);
1380
				}
1381
			}, false);
1382
			mediaElement.addEventListener("durationchange", function() {
1383
				if(entity.gate) {
1384
					self._getHtmlStatus(mediaElement);
1385
					self._updateInterface();
1386
					self._trigger($.jPlayer.event.durationchange);
1387
				}
1388
			}, false);
1389
			mediaElement.addEventListener("play", function() {
1390
				if(entity.gate) {
1391
					self._updateButtons(true);
1392
					self._html_checkWaitForPlay(); // So the native controls update this variable and puts the hidden interface in the correct state. Affects toggling native controls.
1393
					self._trigger($.jPlayer.event.play);
1394
				}
1395
			}, false);
1396
			mediaElement.addEventListener("playing", function() {
1397
				if(entity.gate) {
1398
					self._updateButtons(true);
1399
					self._seeked();
1400
					self._trigger($.jPlayer.event.playing);
1401
				}
1402
			}, false);
1403
			mediaElement.addEventListener("pause", function() {
1404
				if(entity.gate) {
1405
					self._updateButtons(false);
1406
					self._trigger($.jPlayer.event.pause);
1407
				}
1408
			}, false);
1409
			mediaElement.addEventListener("waiting", function() {
1410
				if(entity.gate) {
1411
					self._seeking();
1412
					self._trigger($.jPlayer.event.waiting);
1413
				}
1414
			}, false);
1415
			mediaElement.addEventListener("seeking", function() {
1416
				if(entity.gate) {
1417
					self._seeking();
1418
					self._trigger($.jPlayer.event.seeking);
1419
				}
1420
			}, false);
1421
			mediaElement.addEventListener("seeked", function() {
1422
				if(entity.gate) {
1423
					self._seeked();
1424
					self._trigger($.jPlayer.event.seeked);
1425
				}
1426
			}, false);
1427
			mediaElement.addEventListener("volumechange", function() {
1428
				if(entity.gate) {
1429
					// Read the values back from the element as the Blackberry PlayBook shares the volume with the physical buttons master volume control.
1430
					// However, when tested 6th July 2011, those buttons do not generate an event. The physical play/pause button does though.
1431
					self.options.volume = mediaElement.volume;
1432
					self.options.muted = mediaElement.muted;
1433
					self._updateMute();
1434
					self._updateVolume();
1435
					self._trigger($.jPlayer.event.volumechange);
1436
				}
1437
			}, false);
1438
			mediaElement.addEventListener("ratechange", function() {
1439
				if(entity.gate) {
1440
					self.options.defaultPlaybackRate = mediaElement.defaultPlaybackRate;
1441
					self.options.playbackRate = mediaElement.playbackRate;
1442
					self._updatePlaybackRate();
1443
					self._trigger($.jPlayer.event.ratechange);
1444
				}
1445
			}, false);
1446
			mediaElement.addEventListener("suspend", function() { // Seems to be the only way of capturing that the iOS4 browser did not actually play the media from the page code. ie., It needs a user gesture.
1447
				if(entity.gate) {
1448
					self._seeked();
1449
					self._trigger($.jPlayer.event.suspend);
1450
				}
1451
			}, false);
1452
			mediaElement.addEventListener("ended", function() {
1453
				if(entity.gate) {
1454
					// Order of the next few commands are important. Change the time and then pause.
1455
					// Solves a bug in Firefox, where issuing pause 1st causes the media to play from the start. ie., The pause is ignored.
1456
					if(!$.jPlayer.browser.webkit) { // Chrome crashes if you do this in conjunction with a setMedia command in an ended event handler. ie., The playlist demo.
1457
						self.htmlElement.media.currentTime = 0; // Safari does not care about this command. ie., It works with or without this line. (Both Safari and Chrome are Webkit.)
1458
					}
1459
					self.htmlElement.media.pause(); // Pause otherwise a click on the progress bar will play from that point, when it shouldn't, since it stopped playback.
1460
					self._updateButtons(false);
1461
					self._getHtmlStatus(mediaElement, true); // With override true. Otherwise Chrome leaves progress at full.
1462
					self._updateInterface();
1463
					self._trigger($.jPlayer.event.ended);
1464
				}
1465
			}, false);
1466
			mediaElement.addEventListener("error", function() {
1467
				if(entity.gate) {
1468
					self._updateButtons(false);
1469
					self._seeked();
1470
					if(self.status.srcSet) { // Deals with case of clearMedia() causing an error event.
1471
						clearTimeout(self.internal.htmlDlyCmdId); // Clears any delayed commands used in the HTML solution.
1472
						self.status.waitForLoad = true; // Allows the load operation to try again.
1473
						self.status.waitForPlay = true; // Reset since a play was captured.
1474
						if(self.status.video && !self.status.nativeVideoControls) {
1475
							self.internal.video.jq.css({'width':'0px', 'height':'0px'});
1476
						}
1477
						if(self._validString(self.status.media.poster) && !self.status.nativeVideoControls) {
1478
							self.internal.poster.jq.show();
1479
						}
1480
						if(self.css.jq.videoPlay.length) {
1481
							self.css.jq.videoPlay.show();
1482
						}
1483
						self._error( {
1484
							type: $.jPlayer.error.URL,
1485
							context: self.status.src, // this.src shows absolute urls. Want context to show the url given.
1486
							message: $.jPlayer.errorMsg.URL,
1487
							hint: $.jPlayer.errorHint.URL
1488
						});
1489
					}
1490
				}
1491
			}, false);
1492
			// Create all the other event listeners that bubble up to a jPlayer event from html, without being used by jPlayer.
1493
			$.each($.jPlayer.htmlEvent, function(i, eventType) {
1494
				mediaElement.addEventListener(this, function() {
1495
					if(entity.gate) {
1496
						self._trigger($.jPlayer.event[eventType]);
1497
					}
1498
				}, false);
1499
			});
1500
		},
1501
		_addAuroraEventListeners : function(player, entity) {
1502
			var self = this;
1503
			//player.preload = this.options.preload;
1504
			//player.muted = this.options.muted;
1505
			player.volume = this.options.volume * 100;
1506
1507
			// Create the event listeners
1508
			// Only want the active entity to affect jPlayer and bubble events.
1509
			// Using entity.gate so that object is referenced and gate property always current
1510
			
1511
			player.on("progress", function() {
1512
				if(entity.gate) {
1513
					if(self.internal.cmdsIgnored && this.readyState > 0) { // Detect iOS executed the command
1514
						self.internal.cmdsIgnored = false;
1515
					}
1516
					self._getAuroraStatus(player);
1517
					self._updateInterface();
1518
					self._trigger($.jPlayer.event.progress);
1519
					// Progress with song duration, we estimate timeupdate need to be triggered too.
1520
					if (player.duration > 0) {
1521
						self._trigger($.jPlayer.event.timeupdate);
1522
					}
1523
				}
1524
			}, false);
1525
			player.on("ready", function() {
1526
				if(entity.gate) {
1527
					self._trigger($.jPlayer.event.loadeddata);
1528
				}
1529
			}, false);
1530
			player.on("duration", function() {
1531
				if(entity.gate) {
1532
					self._getAuroraStatus(player);
1533
					self._updateInterface();
1534
					self._trigger($.jPlayer.event.durationchange);
1535
				}
1536
			}, false);
1537
			player.on("end", function() {
1538
				if(entity.gate) {
1539
					// Order of the next few commands are important. Change the time and then pause.
1540
					self._updateButtons(false);
1541
					self._getAuroraStatus(player, true);
1542
					self._updateInterface();
1543
					self._trigger($.jPlayer.event.ended);
1544
				}
1545
			}, false);
1546
			player.on("error", function() {
1547
				if(entity.gate) {
1548
					self._updateButtons(false);
1549
					self._seeked();
1550
					if(self.status.srcSet) { // Deals with case of clearMedia() causing an error event.
1551
						self.status.waitForLoad = true; // Allows the load operation to try again.
1552
						self.status.waitForPlay = true; // Reset since a play was captured.
1553
						if(self.status.video && !self.status.nativeVideoControls) {
1554
							self.internal.video.jq.css({'width':'0px', 'height':'0px'});
1555
						}
1556
						if(self._validString(self.status.media.poster) && !self.status.nativeVideoControls) {
1557
							self.internal.poster.jq.show();
1558
						}
1559
						if(self.css.jq.videoPlay.length) {
1560
							self.css.jq.videoPlay.show();
1561
						}
1562
						self._error( {
1563
							type: $.jPlayer.error.URL,
1564
							context: self.status.src, // this.src shows absolute urls. Want context to show the url given.
1565
							message: $.jPlayer.errorMsg.URL,
1566
							hint: $.jPlayer.errorHint.URL
1567
						});
1568
					}
1569
				}
1570
			}, false);
1571
		},
1572
		_getHtmlStatus: function(media, override) {
1573
			var ct = 0, cpa = 0, sp = 0, cpr = 0;
1574
1575
			// Fixes the duration bug in iOS, where the durationchange event occurs when media.duration is not always correct.
1576
			// Fixes the initial duration bug in BB OS7, where the media.duration is infinity and displays as NaN:NaN due to Date() using inifity.
1577
			if(isFinite(media.duration)) {
1578
				this.status.duration = media.duration;
1579
			}
1580
1581
			ct = media.currentTime;
1582
			cpa = (this.status.duration > 0) ? 100 * ct / this.status.duration : 0;
1583
			if((typeof media.seekable === "object") && (media.seekable.length > 0)) {
1584
				sp = (this.status.duration > 0) ? 100 * media.seekable.end(media.seekable.length-1) / this.status.duration : 100;
1585
				cpr = (this.status.duration > 0) ? 100 * media.currentTime / media.seekable.end(media.seekable.length-1) : 0; // Duration conditional for iOS duration bug. ie., seekable.end is a NaN in that case.
1586
			} else {
1587
				sp = 100;
1588
				cpr = cpa;
1589
			}
1590
			
1591
			if(override) {
1592
				ct = 0;
1593
				cpr = 0;
1594
				cpa = 0;
1595
			}
1596
1597
			this.status.seekPercent = sp;
1598
			this.status.currentPercentRelative = cpr;
1599
			this.status.currentPercentAbsolute = cpa;
1600
			this.status.currentTime = ct;
1601
1602
			this.status.remaining = this.status.duration - this.status.currentTime;
1603
1604
			this.status.videoWidth = media.videoWidth;
1605
			this.status.videoHeight = media.videoHeight;
1606
1607
			this.status.readyState = media.readyState;
1608
			this.status.networkState = media.networkState;
1609
			this.status.playbackRate = media.playbackRate;
1610
			this.status.ended = media.ended;
1611
		},
1612
		_getAuroraStatus: function(player, override) {
1613
			var ct = 0, cpa = 0, sp = 0, cpr = 0;
1614
1615
			this.status.duration = player.duration / 1000;
1616
1617
			ct = player.currentTime / 1000;
1618
			cpa = (this.status.duration > 0) ? 100 * ct / this.status.duration : 0;
1619
			if(player.buffered > 0) {
1620
				sp = (this.status.duration > 0) ? (player.buffered * this.status.duration) / this.status.duration : 100;
1621
				cpr = (this.status.duration > 0) ? ct / (player.buffered * this.status.duration) : 0;
1622
			} else {
1623
				sp = 100;
1624
				cpr = cpa;
1625
			}
1626
			
1627
			if(override) {
1628
				ct = 0;
1629
				cpr = 0;
1630
				cpa = 0;
1631
			}
1632
1633
			this.status.seekPercent = sp;
1634
			this.status.currentPercentRelative = cpr;
1635
			this.status.currentPercentAbsolute = cpa;
1636
			this.status.currentTime = ct;
1637
1638
			this.status.remaining = this.status.duration - this.status.currentTime;
1639
1640
			this.status.readyState = 4; // status.readyState;
1641
			this.status.networkState = 0; // status.networkState;
1642
			this.status.playbackRate = 1; // status.playbackRate;
1643
			this.status.ended = false; // status.ended;
1644
		},
1645
		_resetStatus: function() {
1646
			this.status = $.extend({}, this.status, $.jPlayer.prototype.status); // Maintains the status properties that persist through a reset.
1647
		},
1648
		_trigger: function(eventType, error, warning) { // eventType always valid as called using $.jPlayer.event.eventType
1649
			var event = $.Event(eventType);
1650
			event.jPlayer = {};
1651
			event.jPlayer.version = $.extend({}, this.version);
1652
			event.jPlayer.options = $.extend(true, {}, this.options); // Deep copy
1653
			event.jPlayer.status = $.extend(true, {}, this.status); // Deep copy
1654
			event.jPlayer.html = $.extend(true, {}, this.html); // Deep copy
1655
			event.jPlayer.aurora = $.extend(true, {}, this.aurora); // Deep copy
1656
			event.jPlayer.flash = $.extend(true, {}, this.flash); // Deep copy
1657
			if(error) {
1658
				event.jPlayer.error = $.extend({}, error);
1659
			}
1660
			if(warning) {
1661
				event.jPlayer.warning = $.extend({}, warning);
1662
			}
1663
			this.element.trigger(event);
1664
		},
1665
		jPlayerFlashEvent: function(eventType, status) { // Called from Flash
1666
			if(eventType === $.jPlayer.event.ready) {
1667
				if(!this.internal.ready) {
1668
					this.internal.ready = true;
1669
					this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Once Flash generates the ready event, minimise to zero as it is not affected by wmode anymore.
1670
1671
					this.version.flash = status.version;
1672
					if(this.version.needFlash !== this.version.flash) {
1673
						this._error( {
1674
							type: $.jPlayer.error.VERSION,
1675
							context: this.version.flash,
1676
							message: $.jPlayer.errorMsg.VERSION + this.version.flash,
1677
							hint: $.jPlayer.errorHint.VERSION
1678
						});
1679
					}
1680
					this._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option.
1681
					this._trigger(eventType);
1682
				} else {
1683
					// This condition occurs if the Flash is hidden and then shown again.
1684
					// Firefox also reloads the Flash if the CSS position changes. position:fixed is used for full screen.
1685
1686
					// Only do this if the Flash is the solution being used at the moment. Affects Media players where both solution may be being used.
1687
					if(this.flash.gate) {
1688
1689
						// Send the current status to the Flash now that it is ready (available) again.
1690
						if(this.status.srcSet) {
1691
1692
							// Need to read original status before issuing the setMedia command.
1693
							var	currentTime = this.status.currentTime,
1694
								paused = this.status.paused; 
1695
1696
							this.setMedia(this.status.media);
1697
							this.volumeWorker(this.options.volume);
1698
							if(currentTime > 0) {
1699
								if(paused) {
1700
									this.pause(currentTime);
1701
								} else {
1702
									this.play(currentTime);
1703
								}
1704
							}
1705
						}
1706
						this._trigger($.jPlayer.event.flashreset);
1707
					}
1708
				}
1709
			}
1710
			if(this.flash.gate) {
1711
				switch(eventType) {
1712
					case $.jPlayer.event.progress:
1713
						this._getFlashStatus(status);
1714
						this._updateInterface();
1715
						this._trigger(eventType);
1716
						break;
1717
					case $.jPlayer.event.timeupdate:
1718
						this._getFlashStatus(status);
1719
						this._updateInterface();
1720
						this._trigger(eventType);
1721
						break;
1722
					case $.jPlayer.event.play:
1723
						this._seeked();
1724
						this._updateButtons(true);
1725
						this._trigger(eventType);
1726
						break;
1727
					case $.jPlayer.event.pause:
1728
						this._updateButtons(false);
1729
						this._trigger(eventType);
1730
						break;
1731
					case $.jPlayer.event.ended:
1732
						this._updateButtons(false);
1733
						this._trigger(eventType);
1734
						break;
1735
					case $.jPlayer.event.click:
1736
						this._trigger(eventType); // This could be dealt with by the default
1737
						break;
1738
					case $.jPlayer.event.error:
1739
						this.status.waitForLoad = true; // Allows the load operation to try again.
1740
						this.status.waitForPlay = true; // Reset since a play was captured.
1741
						if(this.status.video) {
1742
							this.internal.flash.jq.css({'width':'0px', 'height':'0px'});
1743
						}
1744
						if(this._validString(this.status.media.poster)) {
1745
							this.internal.poster.jq.show();
1746
						}
1747
						if(this.css.jq.videoPlay.length && this.status.video) {
1748
							this.css.jq.videoPlay.show();
1749
						}
1750
						if(this.status.video) { // Set up for another try. Execute before error event.
1751
							this._flash_setVideo(this.status.media);
1752
						} else {
1753
							this._flash_setAudio(this.status.media);
1754
						}
1755
						this._updateButtons(false);
1756
						this._error( {
1757
							type: $.jPlayer.error.URL,
1758
							context:status.src,
1759
							message: $.jPlayer.errorMsg.URL,
1760
							hint: $.jPlayer.errorHint.URL
1761
						});
1762
						break;
1763
					case $.jPlayer.event.seeking:
1764
						this._seeking();
1765
						this._trigger(eventType);
1766
						break;
1767
					case $.jPlayer.event.seeked:
1768
						this._seeked();
1769
						this._trigger(eventType);
1770
						break;
1771
					case $.jPlayer.event.ready:
1772
						// The ready event is handled outside the switch statement.
1773
						// Captured here otherwise 2 ready events would be generated if the ready event handler used setMedia.
1774
						break;
1775
					default:
1776
						this._trigger(eventType);
1777
				}
1778
			}
1779
			return false;
1780
		},
1781
		_getFlashStatus: function(status) {
1782
			this.status.seekPercent = status.seekPercent;
1783
			this.status.currentPercentRelative = status.currentPercentRelative;
1784
			this.status.currentPercentAbsolute = status.currentPercentAbsolute;
1785
			this.status.currentTime = status.currentTime;
1786
			this.status.duration = status.duration;
1787
			this.status.remaining = status.duration - status.currentTime;
1788
1789
			this.status.videoWidth = status.videoWidth;
1790
			this.status.videoHeight = status.videoHeight;
1791
1792
			// The Flash does not generate this information in this release
1793
			this.status.readyState = 4; // status.readyState;
1794
			this.status.networkState = 0; // status.networkState;
1795
			this.status.playbackRate = 1; // status.playbackRate;
1796
			this.status.ended = false; // status.ended;
1797
		},
1798
		_updateButtons: function(playing) {
1799
			if(playing === undefined) {
1800
				playing = !this.status.paused;
1801
			} else {
1802
				this.status.paused = !playing;
1803
			}
1804
			// Apply the state classes. (For the useStateClassSkin:true option)
1805
			if(playing) {
1806
				this.addStateClass('playing');
1807
			} else {
1808
				this.removeStateClass('playing');
1809
			}
1810
			if(!this.status.noFullWindow && this.options.fullWindow) {
1811
				this.addStateClass('fullScreen');
1812
			} else {
1813
				this.removeStateClass('fullScreen');
1814
			}
1815
			if(this.options.loop) {
1816
				this.addStateClass('looped');
1817
			} else {
1818
				this.removeStateClass('looped');
1819
			}
1820
			// Toggle the GUI element pairs. (For the useStateClassSkin:false option)
1821
			if(this.css.jq.play.length && this.css.jq.pause.length) {
1822
				if(playing) {
1823
					this.css.jq.play.hide();
1824
					this.css.jq.pause.show();
1825
				} else {
1826
					this.css.jq.play.show();
1827
					this.css.jq.pause.hide();
1828
				}
1829
			}
1830
			if(this.css.jq.restoreScreen.length && this.css.jq.fullScreen.length) {
1831
				if(this.status.noFullWindow) {
1832
					this.css.jq.fullScreen.hide();
1833
					this.css.jq.restoreScreen.hide();
1834
				} else if(this.options.fullWindow) {
1835
					this.css.jq.fullScreen.hide();
1836
					this.css.jq.restoreScreen.show();
1837
				} else {
1838
					this.css.jq.fullScreen.show();
1839
					this.css.jq.restoreScreen.hide();
1840
				}
1841
			}
1842
			if(this.css.jq.repeat.length && this.css.jq.repeatOff.length) {
1843
				if(this.options.loop) {
1844
					this.css.jq.repeat.hide();
1845
					this.css.jq.repeatOff.show();
1846
				} else {
1847
					this.css.jq.repeat.show();
1848
					this.css.jq.repeatOff.hide();
1849
				}
1850
			}
1851
		},
1852
		_updateInterface: function() {
1853
			if(this.css.jq.seekBar.length) {
1854
				this.css.jq.seekBar.width(this.status.seekPercent+"%");
1855
			}
1856
			if(this.css.jq.playBar.length) {
1857
				if(this.options.smoothPlayBar) {
1858
					this.css.jq.playBar.stop().animate({
1859
						width: this.status.currentPercentAbsolute+"%"
1860
					}, 250, "linear");
1861
				} else {
1862
					this.css.jq.playBar.width(this.status.currentPercentRelative+"%");
1863
				}
1864
			}
1865
			var currentTimeText = '';
1866
			if(this.css.jq.currentTime.length) {
1867
				currentTimeText = this._convertTime(this.status.currentTime);
1868
				if(currentTimeText !== this.css.jq.currentTime.text()) {
1869
					this.css.jq.currentTime.text(this._convertTime(this.status.currentTime));
1870
				}
1871
			}
1872
			var durationText = '',
1873
				duration = this.status.duration,
1874
				remaining = this.status.remaining;
1875
			if(this.css.jq.duration.length) {
1876
				if(typeof this.status.media.duration === 'string') {
1877
					durationText = this.status.media.duration;
1878
				} else {
1879
					if(typeof this.status.media.duration === 'number') {
1880
						duration = this.status.media.duration;
1881
						remaining = duration - this.status.currentTime;
1882
					}
1883
					if(this.options.remainingDuration) {
1884
						durationText = (remaining > 0 ? '-' : '') + this._convertTime(remaining);
1885
					} else {
1886
						durationText = this._convertTime(duration);
1887
					}
1888
				}
1889
				if(durationText !== this.css.jq.duration.text()) {
1890
					this.css.jq.duration.text(durationText);
1891
				}
1892
			}
1893
		},
1894
		_convertTime: ConvertTime.prototype.time,
1895
		_seeking: function() {
1896
			if(this.css.jq.seekBar.length) {
1897
				this.css.jq.seekBar.addClass("jp-seeking-bg");
1898
			}
1899
			this.addStateClass('seeking');
1900
		},
1901
		_seeked: function() {
1902
			if(this.css.jq.seekBar.length) {
1903
				this.css.jq.seekBar.removeClass("jp-seeking-bg");
1904
			}
1905
			this.removeStateClass('seeking');
1906
		},
1907
		_resetGate: function() {
1908
			this.html.audio.gate = false;
1909
			this.html.video.gate = false;
1910
			this.aurora.gate = false;
1911
			this.flash.gate = false;
1912
		},
1913
		_resetActive: function() {
1914
			this.html.active = false;
1915
			this.aurora.active = false;
1916
			this.flash.active = false;
1917
		},
1918
		_escapeHtml: function(s) {
1919
			return s.split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;').split('"').join('&quot;');
1920
		},
1921
		_qualifyURL: function(url) {
1922
			var el = document.createElement('div');
1923
			el.innerHTML= '<a href="' + this._escapeHtml(url) + '">x</a>';
1924
			return el.firstChild.href;
1925
		},
1926
		_absoluteMediaUrls: function(media) {
1927
			var self = this;
1928
			$.each(media, function(type, url) {
1929
				if(url && self.format[type] && url.substr(0, 5) !== "data:") {
1930
					media[type] = self._qualifyURL(url);
1931
				}
1932
			});
1933
			return media;
1934
		},
1935
		addStateClass: function(state) {
1936
			if(this.ancestorJq.length) {
1937
				this.ancestorJq.addClass(this.options.stateClass[state]);
1938
			}
1939
		},
1940
		removeStateClass: function(state) {
1941
			if(this.ancestorJq.length) {
1942
				this.ancestorJq.removeClass(this.options.stateClass[state]);
1943
			}
1944
		},
1945
		setMedia: function(media) {
1946
		
1947
			/*	media[format] = String: URL of format. Must contain all of the supplied option's video or audio formats.
1948
			 *	media.poster = String: Video poster URL.
1949
			 *	media.track = Array: Of objects defining the track element: kind, src, srclang, label, def.
1950
			 *	media.stream = Boolean: * NOT IMPLEMENTED * Designating actual media streams. ie., "false/undefined" for files. Plan to refresh the flash every so often.
1951
			 */
1952
1953
			var	self = this,
1954
				supported = false,
1955
				posterChanged = this.status.media.poster !== media.poster; // Compare before reset. Important for OSX Safari as this.htmlElement.poster.src is absolute, even if original poster URL was relative.
1956
1957
			this._resetMedia();
1958
			this._resetGate();
1959
			this._resetActive();
1960
1961
			// Clear the Android Fix.
1962
			this.androidFix.setMedia = false;
1963
			this.androidFix.play = false;
1964
			this.androidFix.pause = false;
1965
1966
			// Convert all media URLs to absolute URLs.
1967
			media = this._absoluteMediaUrls(media);
1968
1969
			$.each(this.formats, function(formatPriority, format) {
1970
				var isVideo = self.format[format].media === 'video';
1971
				$.each(self.solutions, function(solutionPriority, solution) {
1972
					if(self[solution].support[format] && self._validString(media[format])) { // Format supported in solution and url given for format.
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if self.solution.support.fo...lidString(media.format) is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
1973
						var isHtml = solution === 'html';
1974
						var isAurora = solution === 'aurora';
1975
1976
						if(isVideo) {
1977
							if(isHtml) {
1978
								self.html.video.gate = true;
1979
								self._html_setVideo(media);
1980
								self.html.active = true;
1981
							} else {
1982
								self.flash.gate = true;
1983
								self._flash_setVideo(media);
1984
								self.flash.active = true;
1985
							}
1986
							if(self.css.jq.videoPlay.length) {
1987
								self.css.jq.videoPlay.show();
1988
							}
1989
							self.status.video = true;
1990
						} else {
1991
							if(isHtml) {
1992
								self.html.audio.gate = true;
1993
								self._html_setAudio(media);
1994
								self.html.active = true;
1995
1996
								// Setup the Android Fix - Only for HTML audio.
1997
								if($.jPlayer.platform.android) {
1998
									self.androidFix.setMedia = true;
1999
								}
2000
							} else if(isAurora) {
2001
								self.aurora.gate = true;
2002
								self._aurora_setAudio(media);
2003
								self.aurora.active = true;
2004
							} else {
2005
								self.flash.gate = true;
2006
								self._flash_setAudio(media);
2007
								self.flash.active = true;
2008
							}
2009
							if(self.css.jq.videoPlay.length) {
2010
								self.css.jq.videoPlay.hide();
2011
							}
2012
							self.status.video = false;
2013
						}
2014
						
2015
						supported = true;
2016
						return false; // Exit $.each
2017
					}
2018
				});
2019
				if(supported) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if supported is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
2020
					return false; // Exit $.each
2021
				}
2022
			});
2023
2024
			if(supported) {
2025
				if(!(this.status.nativeVideoControls && this.html.video.gate)) {
2026
					// Set poster IMG if native video controls are not being used
2027
					// Note: With IE the IMG onload event occurs immediately when cached.
2028
					// Note: Poster hidden by default in _resetMedia()
2029
					if(this._validString(media.poster)) {
2030
						if(posterChanged) { // Since some browsers do not generate img onload event.
2031
							this.htmlElement.poster.src = media.poster;
2032
						} else {
2033
							this.internal.poster.jq.show();
2034
						}
2035
					}
2036
				}
2037
				if(typeof media.title === 'string') {
2038
					if(this.css.jq.title.length) {
2039
						this.css.jq.title.html(media.title);
2040
					}
2041
					if(this.htmlElement.audio) {
2042
						this.htmlElement.audio.setAttribute('title', media.title);
2043
					}
2044
					if(this.htmlElement.video) {
2045
						this.htmlElement.video.setAttribute('title', media.title);
2046
					}
2047
				}
2048
				this.status.srcSet = true;
2049
				this.status.media = $.extend({}, media);
2050
				this._updateButtons(false);
2051
				this._updateInterface();
2052
				this._trigger($.jPlayer.event.setmedia);
2053
			} else { // jPlayer cannot support any formats provided in this browser
2054
				// Send an error event
2055
				this._error( {
2056
					type: $.jPlayer.error.NO_SUPPORT,
2057
					context: "{supplied:'" + this.options.supplied + "'}",
2058
					message: $.jPlayer.errorMsg.NO_SUPPORT,
2059
					hint: $.jPlayer.errorHint.NO_SUPPORT
2060
				});
2061
			}
2062
		},
2063
		_resetMedia: function() {
2064
			this._resetStatus();
2065
			this._updateButtons(false);
2066
			this._updateInterface();
2067
			this._seeked();
2068
			this.internal.poster.jq.hide();
2069
2070
			clearTimeout(this.internal.htmlDlyCmdId);
2071
2072
			if(this.html.active) {
2073
				this._html_resetMedia();
2074
			} else if(this.aurora.active) {
2075
				this._aurora_resetMedia();
2076
			} else if(this.flash.active) {
2077
				this._flash_resetMedia();
2078
			}
2079
		},
2080
		clearMedia: function() {
2081
			this._resetMedia();
2082
2083
			if(this.html.active) {
2084
				this._html_clearMedia();
2085
			} else if(this.aurora.active) {
2086
				this._aurora_clearMedia();
2087
			} else if(this.flash.active) {
2088
				this._flash_clearMedia();
2089
			}
2090
2091
			this._resetGate();
2092
			this._resetActive();
2093
		},
2094
		load: function() {
2095
			if(this.status.srcSet) {
2096
				if(this.html.active) {
2097
					this._html_load();
2098
				} else if(this.aurora.active) {
2099
					this._aurora_load();
2100
				} else if(this.flash.active) {
2101
					this._flash_load();
2102
				}
2103
			} else {
2104
				this._urlNotSetError("load");
2105
			}
2106
		},
2107
		focus: function() {
2108
			if(this.options.keyEnabled) {
2109
				$.jPlayer.focus = this;
2110
			}
2111
		},
2112
		play: function(time) {
2113
			var guiAction = typeof time === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
2114
			if(guiAction && this.options.useStateClassSkin && !this.status.paused) {
2115
				this.pause(time); // The time would be the click event, but passing it over so info is not lost.
2116
			} else {
2117
				time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler
2118
				if(this.status.srcSet) {
2119
					this.focus();
2120
					if(this.html.active) {
2121
						this._html_play(time);
2122
					} else if(this.aurora.active) {
2123
						this._aurora_play(time);
2124
					} else if(this.flash.active) {
2125
						this._flash_play(time);
2126
					}
2127
				} else {
2128
					this._urlNotSetError("play");
2129
				}
2130
			}
2131
		},
2132
		videoPlay: function() { // Handles clicks on the play button over the video poster
2133
			this.play();
2134
		},
2135
		pause: function(time) {
2136
			time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler
2137
			if(this.status.srcSet) {
2138
				if(this.html.active) {
2139
					this._html_pause(time);
2140
				} else if(this.aurora.active) {
2141
					this._aurora_pause(time);
2142
				} else if(this.flash.active) {
2143
					this._flash_pause(time);
2144
				}
2145
			} else {
2146
				this._urlNotSetError("pause");
2147
			}
2148
		},
2149
		tellOthers: function(command, conditions) {
2150
			var self = this,
2151
				hasConditions = typeof conditions === 'function',
2152
				args = Array.prototype.slice.call(arguments); // Convert arguments to an Array.
2153
2154
			if(typeof command !== 'string') { // Ignore, since no command.
2155
				return; // Return undefined to maintain chaining.
2156
			}
2157
			if(hasConditions) {
2158
				args.splice(1, 1); // Remove the conditions from the arguments
2159
			}
2160
2161
			$.jPlayer.prototype.destroyRemoved();
2162
			$.each(this.instances, function() {
2163
				// Remember that "this" is the instance's "element" in the $.each() loop.
2164
				if(self.element !== this) { // Do not tell my instance.
2165
					if(!hasConditions || conditions.call(this.data("jPlayer"), self)) {
2166
						this.jPlayer.apply(this, args);
2167
					}
2168
				}
2169
			});
2170
		},
2171
		pauseOthers: function(time) {
2172
			this.tellOthers("pause", function() {
2173
				// In the conditions function, the "this" context is the other instance's jPlayer object.
2174
				return this.status.srcSet;
2175
			}, time);
2176
		},
2177
		stop: function() {
2178
			if(this.status.srcSet) {
2179
				if(this.html.active) {
2180
					this._html_pause(0);
2181
				} else if(this.aurora.active) {
2182
					this._aurora_pause(0);
2183
				} else if(this.flash.active) {
2184
					this._flash_pause(0);
2185
				}
2186
			} else {
2187
				this._urlNotSetError("stop");
2188
			}
2189
		},
2190
		playHead: function(p) {
2191
			p = this._limitValue(p, 0, 100);
2192
			if(this.status.srcSet) {
2193
				if(this.html.active) {
2194
					this._html_playHead(p);
2195
				} else if(this.aurora.active) {
2196
					this._aurora_playHead(p);
2197
				} else if(this.flash.active) {
2198
					this._flash_playHead(p);
2199
				}
2200
			} else {
2201
				this._urlNotSetError("playHead");
2202
			}
2203
		},
2204
		_muted: function(muted) {
2205
			this.mutedWorker(muted);
2206
			if(this.options.globalVolume) {
2207
				this.tellOthers("mutedWorker", function() {
2208
					// Check the other instance has global volume enabled.
2209
					return this.options.globalVolume;
2210
				}, muted);
2211
			}
2212
		},
2213
		mutedWorker: function(muted) {
2214
			this.options.muted = muted;
2215
			if(this.html.used) {
2216
				this._html_setProperty('muted', muted);
2217
			}
2218
			if(this.aurora.used) {
2219
				this._aurora_mute(muted);
2220
			}
2221
			if(this.flash.used) {
2222
				this._flash_mute(muted);
2223
			}
2224
2225
			// The HTML solution generates this event from the media element itself.
2226
			if(!this.html.video.gate && !this.html.audio.gate) {
2227
				this._updateMute(muted);
2228
				this._updateVolume(this.options.volume);
2229
				this._trigger($.jPlayer.event.volumechange);
2230
			}
2231
		},
2232
		mute: function(mute) { // mute is either: undefined (true), an event object (true) or a boolean (muted).
2233
			var guiAction = typeof mute === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
2234
			if(guiAction && this.options.useStateClassSkin && this.options.muted) {
2235
				this._muted(false);
2236
			} else {
2237
				mute = mute === undefined ? true : !!mute;
2238
				this._muted(mute);
2239
			}
2240
		},
2241
		unmute: function(unmute) { // unmute is either: undefined (true), an event object (true) or a boolean (!muted).
2242
			unmute = unmute === undefined ? true : !!unmute;
2243
			this._muted(!unmute);
2244
		},
2245
		_updateMute: function(mute) {
2246
			if(mute === undefined) {
2247
				mute = this.options.muted;
2248
			}
2249
			if(mute) {
2250
				this.addStateClass('muted');
2251
			} else {
2252
				this.removeStateClass('muted');
2253
			}
2254
			if(this.css.jq.mute.length && this.css.jq.unmute.length) {
2255
				if(this.status.noVolume) {
2256
					this.css.jq.mute.hide();
2257
					this.css.jq.unmute.hide();
2258
				} else if(mute) {
2259
					this.css.jq.mute.hide();
2260
					this.css.jq.unmute.show();
2261
				} else {
2262
					this.css.jq.mute.show();
2263
					this.css.jq.unmute.hide();
2264
				}
2265
			}
2266
		},
2267
		volume: function(v) {
2268
			this.volumeWorker(v);
2269
			if(this.options.globalVolume) {
2270
				this.tellOthers("volumeWorker", function() {
2271
					// Check the other instance has global volume enabled.
2272
					return this.options.globalVolume;
2273
				}, v);
2274
			}
2275
		},
2276
		volumeWorker: function(v) {
2277
			v = this._limitValue(v, 0, 1);
2278
			this.options.volume = v;
2279
2280
			if(this.html.used) {
2281
				this._html_setProperty('volume', v);
2282
			}
2283
			if(this.aurora.used) {
2284
				this._aurora_volume(v);
2285
			}
2286
			if(this.flash.used) {
2287
				this._flash_volume(v);
2288
			}
2289
2290
			// The HTML solution generates this event from the media element itself.
2291
			if(!this.html.video.gate && !this.html.audio.gate) {
2292
				this._updateVolume(v);
2293
				this._trigger($.jPlayer.event.volumechange);
2294
			}
2295
		},
2296
		volumeBar: function(e) { // Handles clicks on the volumeBar
2297
			if(this.css.jq.volumeBar.length) {
2298
				// Using $(e.currentTarget) to enable multiple volume bars
2299
				var $bar = $(e.currentTarget),
2300
					offset = $bar.offset(),
2301
					x = e.pageX - offset.left,
2302
					w = $bar.width(),
2303
					y = $bar.height() - e.pageY + offset.top,
2304
					h = $bar.height();
2305
				if(this.options.verticalVolume) {
2306
					this.volume(y/h);
2307
				} else {
2308
					this.volume(x/w);
2309
				}
2310
			}
2311
			if(this.options.muted) {
2312
				this._muted(false);
2313
			}
2314
		},
2315
		_updateVolume: function(v) {
2316
			if(v === undefined) {
2317
				v = this.options.volume;
2318
			}
2319
			v = this.options.muted ? 0 : v;
2320
2321
			if(this.status.noVolume) {
2322
				this.addStateClass('noVolume');
2323
				if(this.css.jq.volumeBar.length) {
2324
					this.css.jq.volumeBar.hide();
2325
				}
2326
				if(this.css.jq.volumeBarValue.length) {
2327
					this.css.jq.volumeBarValue.hide();
2328
				}
2329
				if(this.css.jq.volumeMax.length) {
2330
					this.css.jq.volumeMax.hide();
2331
				}
2332
			} else {
2333
				this.removeStateClass('noVolume');
2334
				if(this.css.jq.volumeBar.length) {
2335
					this.css.jq.volumeBar.show();
2336
				}
2337
				if(this.css.jq.volumeBarValue.length) {
2338
					this.css.jq.volumeBarValue.show();
2339
					this.css.jq.volumeBarValue[this.options.verticalVolume ? "height" : "width"]((v*100)+"%");
2340
				}
2341
				if(this.css.jq.volumeMax.length) {
2342
					this.css.jq.volumeMax.show();
2343
				}
2344
			}
2345
		},
2346
		volumeMax: function() { // Handles clicks on the volume max
2347
			this.volume(1);
2348
			if(this.options.muted) {
2349
				this._muted(false);
2350
			}
2351
		},
2352
		_cssSelectorAncestor: function(ancestor) {
2353
			var self = this;
2354
			this.options.cssSelectorAncestor = ancestor;
2355
			this._removeUiClass();
2356
			this.ancestorJq = ancestor ? $(ancestor) : []; // Would use $() instead of [], but it is only 1.4+
2357
			if(ancestor && this.ancestorJq.length !== 1) { // So empty strings do not generate the warning.
2358
				this._warning( {
2359
					type: $.jPlayer.warning.CSS_SELECTOR_COUNT,
2360
					context: ancestor,
2361
					message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.ancestorJq.length + " found for cssSelectorAncestor.",
2362
					hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT
2363
				});
2364
			}
2365
			this._addUiClass();
2366
			$.each(this.options.cssSelector, function(fn, cssSel) {
2367
				self._cssSelector(fn, cssSel);
2368
			});
2369
2370
			// Set the GUI to the current state.
2371
			this._updateInterface();
2372
			this._updateButtons();
2373
			this._updateAutohide();
2374
			this._updateVolume();
2375
			this._updateMute();
2376
		},
2377
		_cssSelector: function(fn, cssSel) {
2378
			var self = this;
2379
			if(typeof cssSel === 'string') {
2380
				if($.jPlayer.prototype.options.cssSelector[fn]) {
2381
					if(this.css.jq[fn] && this.css.jq[fn].length) {
2382
						this.css.jq[fn].unbind(".jPlayer");
2383
					}
2384
					this.options.cssSelector[fn] = cssSel;
2385
					this.css.cs[fn] = this.options.cssSelectorAncestor + " " + cssSel;
2386
2387
					if(cssSel) { // Checks for empty string
2388
						this.css.jq[fn] = $(this.css.cs[fn]);
2389
					} else {
2390
						this.css.jq[fn] = []; // To comply with the css.jq[fn].length check before its use. As of jQuery 1.4 could have used $() for an empty set. 
2391
					}
2392
2393
					if(this.css.jq[fn].length && this[fn]) {
2394
						var handler = function(e) {
2395
							e.preventDefault();
2396
							self[fn](e);
2397
							if(self.options.autoBlur) {
2398
								$(this).blur();
2399
							} else {
2400
								$(this).focus(); // Force focus for ARIA.
2401
							}
2402
						};
2403
						this.css.jq[fn].bind("click.jPlayer", handler); // Using jPlayer namespace
2404
					}
2405
2406
					if(cssSel && this.css.jq[fn].length !== 1) { // So empty strings do not generate the warning. ie., they just remove the old one.
2407
						this._warning( {
2408
							type: $.jPlayer.warning.CSS_SELECTOR_COUNT,
2409
							context: this.css.cs[fn],
2410
							message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.css.jq[fn].length + " found for " + fn + " method.",
2411
							hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT
2412
						});
2413
					}
2414
				} else {
2415
					this._warning( {
2416
						type: $.jPlayer.warning.CSS_SELECTOR_METHOD,
2417
						context: fn,
2418
						message: $.jPlayer.warningMsg.CSS_SELECTOR_METHOD,
2419
						hint: $.jPlayer.warningHint.CSS_SELECTOR_METHOD
2420
					});
2421
				}
2422
			} else {
2423
				this._warning( {
2424
					type: $.jPlayer.warning.CSS_SELECTOR_STRING,
2425
					context: cssSel,
2426
					message: $.jPlayer.warningMsg.CSS_SELECTOR_STRING,
2427
					hint: $.jPlayer.warningHint.CSS_SELECTOR_STRING
2428
				});
2429
			}
2430
		},
2431
		duration: function(e) {
2432
			if(this.options.toggleDuration) {
2433
				if(this.options.captureDuration) {
2434
					e.stopPropagation();
2435
				}
2436
				this._setOption("remainingDuration", !this.options.remainingDuration);
2437
			}
2438
		},
2439
		seekBar: function(e) { // Handles clicks on the seekBar
2440
			if(this.css.jq.seekBar.length) {
2441
				// Using $(e.currentTarget) to enable multiple seek bars
2442
				var $bar = $(e.currentTarget),
2443
					offset = $bar.offset(),
2444
					x = e.pageX - offset.left,
2445
					w = $bar.width(),
2446
					p = 100 * x / w;
2447
				this.playHead(p);
2448
			}
2449
		},
2450
		playbackRate: function(pbr) {
2451
			this._setOption("playbackRate", pbr);
2452
		},
2453
		playbackRateBar: function(e) { // Handles clicks on the playbackRateBar
2454
			if(this.css.jq.playbackRateBar.length) {
2455
				// Using $(e.currentTarget) to enable multiple playbackRate bars
2456
				var $bar = $(e.currentTarget),
2457
					offset = $bar.offset(),
2458
					x = e.pageX - offset.left,
2459
					w = $bar.width(),
2460
					y = $bar.height() - e.pageY + offset.top,
2461
					h = $bar.height(),
2462
					ratio, pbr;
2463
				if(this.options.verticalPlaybackRate) {
2464
					ratio = y/h;
2465
				} else {
2466
					ratio = x/w;
2467
				}
2468
				pbr = ratio * (this.options.maxPlaybackRate - this.options.minPlaybackRate) + this.options.minPlaybackRate;
2469
				this.playbackRate(pbr);
2470
			}
2471
		},
2472
		_updatePlaybackRate: function() {
2473
			var pbr = this.options.playbackRate,
2474
				ratio = (pbr - this.options.minPlaybackRate) / (this.options.maxPlaybackRate - this.options.minPlaybackRate);
2475
			if(this.status.playbackRateEnabled) {
2476
				if(this.css.jq.playbackRateBar.length) {
2477
					this.css.jq.playbackRateBar.show();
2478
				}
2479
				if(this.css.jq.playbackRateBarValue.length) {
2480
					this.css.jq.playbackRateBarValue.show();
2481
					this.css.jq.playbackRateBarValue[this.options.verticalPlaybackRate ? "height" : "width"]((ratio*100)+"%");
2482
				}
2483
			} else {
2484
				if(this.css.jq.playbackRateBar.length) {
2485
					this.css.jq.playbackRateBar.hide();
2486
				}
2487
				if(this.css.jq.playbackRateBarValue.length) {
2488
					this.css.jq.playbackRateBarValue.hide();
2489
				}
2490
			}
2491
		},
2492
		repeat: function(event) { // Handle clicks on the repeat button
2493
			var guiAction = typeof event === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
2494
			if(guiAction && this.options.useStateClassSkin && this.options.loop) {
2495
				this._loop(false);
2496
			} else {
2497
				this._loop(true);
2498
			}
2499
		},
2500
		repeatOff: function() { // Handle clicks on the repeatOff button
2501
			this._loop(false);
2502
		},
2503
		_loop: function(loop) {
2504
			if(this.options.loop !== loop) {
2505
				this.options.loop = loop;
2506
				this._updateButtons();
2507
				this._trigger($.jPlayer.event.repeat);
2508
			}
2509
		},
2510
2511
		// Options code adapted from ui.widget.js (1.8.7).  Made changes so the key can use dot notation. To match previous getData solution in jPlayer 1.
2512
		option: function(key, value) {
2513
			var options = key;
2514
2515
			 // Enables use: options().  Returns a copy of options object
2516
			if ( arguments.length === 0 ) {
2517
				return $.extend( true, {}, this.options );
2518
			}
2519
2520
			if(typeof key === "string") {
2521
				var keys = key.split(".");
2522
2523
				 // Enables use: options("someOption")  Returns a copy of the option. Supports dot notation.
2524
				if(value === undefined) {
2525
2526
					var opt = $.extend(true, {}, this.options);
2527
					for(var i = 0; i < keys.length; i++) {
2528
						if(opt[keys[i]] !== undefined) {
2529
							opt = opt[keys[i]];
2530
						} else {
2531
							this._warning( {
2532
								type: $.jPlayer.warning.OPTION_KEY,
2533
								context: key,
2534
								message: $.jPlayer.warningMsg.OPTION_KEY,
2535
								hint: $.jPlayer.warningHint.OPTION_KEY
2536
							});
2537
							return undefined;
2538
						}
2539
					}
2540
					return opt;
2541
				}
2542
2543
				 // Enables use: options("someOptionObject", someObject}).  Creates: {someOptionObject:someObject}
2544
				 // Enables use: options("someOption", someValue).  Creates: {someOption:someValue}
2545
				 // Enables use: options("someOptionObject.someOption", someValue).  Creates: {someOptionObject:{someOption:someValue}}
2546
2547
				options = {};
2548
				var opts = options;
2549
2550
				for(var j = 0; j < keys.length; j++) {
2551
					if(j < keys.length - 1) {
2552
						opts[keys[j]] = {};
2553
						opts = opts[keys[j]];
2554
					} else {
2555
						opts[keys[j]] = value;
2556
					}
2557
				}
2558
			}
2559
2560
			 // Otherwise enables use: options(optionObject).  Uses original object (the key)
2561
2562
			this._setOptions(options);
2563
2564
			return this;
2565
		},
2566
		_setOptions: function(options) {
2567
			var self = this;
2568
			$.each(options, function(key, value) { // This supports the 2 level depth that the options of jPlayer has. Would review if we ever need more depth.
2569
				self._setOption(key, value);
2570
			});
2571
2572
			return this;
2573
		},
2574
		_setOption: function(key, value) {
2575
			var self = this;
2576
2577
			// The ability to set options is limited at this time.
2578
2579
			switch(key) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
2580
				case "volume" :
2581
					this.volume(value);
2582
					break;
2583
				case "muted" :
2584
					this._muted(value);
2585
					break;
2586
				case "globalVolume" :
2587
					this.options[key] = value;
2588
					break;
2589
				case "cssSelectorAncestor" :
2590
					this._cssSelectorAncestor(value); // Set and refresh all associations for the new ancestor.
2591
					break;
2592
				case "cssSelector" :
2593
					$.each(value, function(fn, cssSel) {
2594
						self._cssSelector(fn, cssSel); // NB: The option is set inside this function, after further validity checks.
2595
					});
2596
					break;
2597
				case "playbackRate" :
2598
					this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate, this.options.maxPlaybackRate);
2599
					if(this.html.used) {
2600
						this._html_setProperty('playbackRate', value);
2601
					}
2602
					this._updatePlaybackRate();
2603
					break;
2604
				case "defaultPlaybackRate" :
2605
					this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate, this.options.maxPlaybackRate);
2606
					if(this.html.used) {
2607
						this._html_setProperty('defaultPlaybackRate', value);
2608
					}
2609
					this._updatePlaybackRate();
2610
					break;
2611
				case "minPlaybackRate" :
2612
					this.options[key] = value = this._limitValue(value, 0.1, this.options.maxPlaybackRate - 0.1);
0 ignored issues
show
Unused Code introduced by
The assignment to variable value seems to be never used. Consider removing it.
Loading history...
2613
					this._updatePlaybackRate();
2614
					break;
2615
				case "maxPlaybackRate" :
2616
					this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate + 0.1, 16);
2617
					this._updatePlaybackRate();
2618
					break;
2619
				case "fullScreen" :
2620
					if(this.options[key] !== value) { // if changed
2621
						var wkv = $.jPlayer.nativeFeatures.fullscreen.used.webkitVideo;
2622
						if(!wkv || wkv && !this.status.waitForPlay) {
2623
							if(!wkv) { // No sensible way to unset option on these devices.
2624
								this.options[key] = value;
2625
							}
2626
							if(value) {
2627
								this._requestFullscreen();
2628
							} else {
2629
								this._exitFullscreen();
2630
							}
2631
							if(!wkv) {
2632
								this._setOption("fullWindow", value);
2633
							}
2634
						}
2635
					}
2636
					break;
2637
				case "fullWindow" :
2638
					if(this.options[key] !== value) { // if changed
2639
						this._removeUiClass();
2640
						this.options[key] = value;
2641
						this._refreshSize();
2642
					}
2643
					break;
2644
				case "size" :
2645
					if(!this.options.fullWindow && this.options[key].cssClass !== value.cssClass) {
2646
						this._removeUiClass();
2647
					}
2648
					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2649
					this._refreshSize();
2650
					break;
2651
				case "sizeFull" :
2652
					if(this.options.fullWindow && this.options[key].cssClass !== value.cssClass) {
2653
						this._removeUiClass();
2654
					}
2655
					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2656
					this._refreshSize();
2657
					break;
2658
				case "autohide" :
2659
					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2660
					this._updateAutohide();
2661
					break;
2662
				case "loop" :
2663
					this._loop(value);
2664
					break;
2665
				case "remainingDuration" :
2666
					this.options[key] = value;
2667
					this._updateInterface();
2668
					break;
2669
				case "toggleDuration" :
2670
					this.options[key] = value;
2671
					break;
2672
				case "nativeVideoControls" :
2673
					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2674
					this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls);
2675
					this._restrictNativeVideoControls();
2676
					this._updateNativeVideoControls();
2677
					break;
2678
				case "noFullWindow" :
2679
					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2680
					this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls); // Need to check again as noFullWindow can depend on this flag and the restrict() can override it.
2681
					this.status.noFullWindow = this._uaBlocklist(this.options.noFullWindow);
2682
					this._restrictNativeVideoControls();
2683
					this._updateButtons();
2684
					break;
2685
				case "noVolume" :
2686
					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2687
					this.status.noVolume = this._uaBlocklist(this.options.noVolume);
2688
					this._updateVolume();
2689
					this._updateMute();
2690
					break;
2691
				case "emulateHtml" :
2692
					if(this.options[key] !== value) { // To avoid multiple event handlers being created, if true already.
2693
						this.options[key] = value;
2694
						if(value) {
2695
							this._emulateHtmlBridge();
2696
						} else {
2697
							this._destroyHtmlBridge();
2698
						}
2699
					}
2700
					break;
2701
				case "timeFormat" :
2702
					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2703
					break;
2704
				case "keyEnabled" :
2705
					this.options[key] = value;
2706
					if(!value && this === $.jPlayer.focus) {
2707
						$.jPlayer.focus = null;
2708
					}
2709
					break;
2710
				case "keyBindings" :
2711
					this.options[key] = $.extend(true, {}, this.options[key], value); // store a merged DEEP copy of it, incase not all properties changed.
2712
					break;
2713
				case "audioFullScreen" :
2714
					this.options[key] = value;
2715
					break;
2716
				case "autoBlur" :
2717
					this.options[key] = value;
2718
					break;
2719
			}
2720
2721
			return this;
2722
		},
2723
		// End of: (Options code adapted from ui.widget.js)
2724
2725
		_refreshSize: function() {
2726
			this._setSize(); // update status and jPlayer element size
2727
			this._addUiClass(); // update the ui class
2728
			this._updateSize(); // update internal sizes
2729
			this._updateButtons();
2730
			this._updateAutohide();
2731
			this._trigger($.jPlayer.event.resize);
2732
		},
2733
		_setSize: function() {
2734
			// Determine the current size from the options
2735
			if(this.options.fullWindow) {
2736
				this.status.width = this.options.sizeFull.width;
2737
				this.status.height = this.options.sizeFull.height;
2738
				this.status.cssClass = this.options.sizeFull.cssClass;
2739
			} else {
2740
				this.status.width = this.options.size.width;
2741
				this.status.height = this.options.size.height;
2742
				this.status.cssClass = this.options.size.cssClass;
2743
			}
2744
2745
			// Set the size of the jPlayer area.
2746
			this.element.css({'width': this.status.width, 'height': this.status.height});
2747
		},
2748
		_addUiClass: function() {
2749
			if(this.ancestorJq.length) {
2750
				this.ancestorJq.addClass(this.status.cssClass);
2751
			}
2752
		},
2753
		_removeUiClass: function() {
2754
			if(this.ancestorJq.length) {
2755
				this.ancestorJq.removeClass(this.status.cssClass);
2756
			}
2757
		},
2758
		_updateSize: function() {
2759
			// The poster uses show/hide so can simply resize it.
2760
			this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height});
2761
2762
			// Video html or flash resized if necessary at this time, or if native video controls being used.
2763
			if(!this.status.waitForPlay && this.html.active && this.status.video || this.html.video.available && this.html.used && this.status.nativeVideoControls) {
2764
				this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
2765
			}
2766
			else if(!this.status.waitForPlay && this.flash.active && this.status.video) {
2767
				this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height});
2768
			}
2769
		},
2770
		_updateAutohide: function() {
2771
			var	self = this,
2772
				event = "mousemove.jPlayer",
2773
				namespace = ".jPlayerAutohide",
2774
				eventType = event + namespace,
2775
				handler = function(event) {
2776
					var moved = false,
0 ignored issues
show
Unused Code introduced by
The assignment to variable moved seems to be never used. Consider removing it.
Loading history...
2777
						deltaX, deltaY;
2778
					if(typeof self.internal.mouse !== "undefined") {
2779
						//get the change from last position to this position
2780
						deltaX = self.internal.mouse.x - event.pageX;
2781
						deltaY = self.internal.mouse.y - event.pageY;
2782
						moved = (Math.floor(deltaX) > 0) || (Math.floor(deltaY)>0); 
2783
					} else {
2784
						moved = true;
2785
					}
2786
					// store current position for next method execution
2787
					self.internal.mouse = {
2788
							x : event.pageX,
2789
							y : event.pageY
2790
					};
2791
					// if mouse has been actually moved, do the gui fadeIn/fadeOut
2792
					if (moved) {
2793
						self.css.jq.gui.fadeIn(self.options.autohide.fadeIn, function() {
2794
							clearTimeout(self.internal.autohideId);
2795
							self.internal.autohideId = setTimeout( function() {
2796
								self.css.jq.gui.fadeOut(self.options.autohide.fadeOut);
2797
							}, self.options.autohide.hold);
2798
						});
2799
					}
2800
				};
2801
2802
			if(this.css.jq.gui.length) {
2803
2804
				// End animations first so that its callback is executed now.
2805
				// Otherwise an in progress fadeIn animation still has the callback to fadeOut again.
2806
				this.css.jq.gui.stop(true, true);
2807
2808
				// Removes the fadeOut operation from the fadeIn callback.
2809
				clearTimeout(this.internal.autohideId);
2810
				// undefine mouse
2811
				delete this.internal.mouse;
2812
2813
				this.element.unbind(namespace);
2814
				this.css.jq.gui.unbind(namespace);
2815
2816
				if(!this.status.nativeVideoControls) {
2817
					if(this.options.fullWindow && this.options.autohide.full || !this.options.fullWindow && this.options.autohide.restored) {
2818
						this.element.bind(eventType, handler);
2819
						this.css.jq.gui.bind(eventType, handler);
2820
						this.css.jq.gui.hide();
2821
					} else {
2822
						this.css.jq.gui.show();
2823
					}
2824
				} else {
2825
					this.css.jq.gui.hide();
2826
				}
2827
			}
2828
		},
2829
		fullScreen: function(event) {
2830
			var guiAction = typeof event === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
2831
			if(guiAction && this.options.useStateClassSkin && this.options.fullScreen) {
2832
				this._setOption("fullScreen", false);
2833
			} else {
2834
				this._setOption("fullScreen", true);
2835
			}
2836
		},
2837
		restoreScreen: function() {
2838
			this._setOption("fullScreen", false);
2839
		},
2840
		_fullscreenAddEventListeners: function() {
2841
			var self = this,
2842
				fs = $.jPlayer.nativeFeatures.fullscreen;
2843
2844
			if(fs.api.fullscreenEnabled) {
2845
				if(fs.event.fullscreenchange) {
2846
					// Create the event handler function and store it for removal.
2847
					if(typeof this.internal.fullscreenchangeHandler !== 'function') {
2848
						this.internal.fullscreenchangeHandler = function() {
2849
							self._fullscreenchange();
2850
						};
2851
					}
2852
					document.addEventListener(fs.event.fullscreenchange, this.internal.fullscreenchangeHandler, false);
2853
				}
2854
				// No point creating handler for fullscreenerror.
2855
				// Either logic avoids fullscreen occurring (w3c/moz), or their is no event on the browser (webkit).
2856
			}
2857
		},
2858
		_fullscreenRemoveEventListeners: function() {
2859
			var fs = $.jPlayer.nativeFeatures.fullscreen;
2860
			if(this.internal.fullscreenchangeHandler) {
2861
				document.removeEventListener(fs.event.fullscreenchange, this.internal.fullscreenchangeHandler, false);
2862
			}
2863
		},
2864
		_fullscreenchange: function() {
2865
			// If nothing is fullscreen, then we cannot be in fullscreen mode.
2866
			if(this.options.fullScreen && !$.jPlayer.nativeFeatures.fullscreen.api.fullscreenElement()) {
2867
				this._setOption("fullScreen", false);
2868
			}
2869
		},
2870
		_requestFullscreen: function() {
2871
			// Either the container or the jPlayer div
2872
			var e = this.ancestorJq.length ? this.ancestorJq[0] : this.element[0],
2873
				fs = $.jPlayer.nativeFeatures.fullscreen;
2874
2875
			// This method needs the video element. For iOS and Android.
2876
			if(fs.used.webkitVideo) {
2877
				e = this.htmlElement.video;
2878
			}
2879
2880
			if(fs.api.fullscreenEnabled) {
2881
				fs.api.requestFullscreen(e);
2882
			}
2883
		},
2884
		_exitFullscreen: function() {
2885
2886
			var fs = $.jPlayer.nativeFeatures.fullscreen,
2887
				e;
2888
2889
			// This method needs the video element. For iOS and Android.
2890
			if(fs.used.webkitVideo) {
2891
				e = this.htmlElement.video;
2892
			}
2893
2894
			if(fs.api.fullscreenEnabled) {
2895
				fs.api.exitFullscreen(e);
0 ignored issues
show
Bug introduced by
The variable e does not seem to be initialized in case fs.used.webkitVideo on line 2890 is false. Are you sure the function exitFullscreen handles undefined variables?
Loading history...
2896
			}
2897
		},
2898
		_html_initMedia: function(media) {
2899
			// Remove any existing track elements
2900
			var $media = $(this.htmlElement.media).empty();
2901
2902
			// Create any track elements given with the media, as an Array of track Objects.
2903
			$.each(media.track || [], function(i,v) {
2904
				var track = document.createElement('track');
2905
				track.setAttribute("kind", v.kind ? v.kind : "");
2906
				track.setAttribute("src", v.src ? v.src : "");
2907
				track.setAttribute("srclang", v.srclang ? v.srclang : "");
2908
				track.setAttribute("label", v.label ? v.label : "");
2909
				if(v.def) {
2910
					track.setAttribute("default", v.def);
2911
				}
2912
				$media.append(track);
2913
			});
2914
2915
			this.htmlElement.media.src = this.status.src;
2916
2917
			if(this.options.preload !== 'none') {
2918
				this._html_load(); // See function for comments
2919
			}
2920
			this._trigger($.jPlayer.event.timeupdate); // The flash generates this event for its solution.
2921
		},
2922
		_html_setFormat: function(media) {
2923
			var self = this;
2924
			// Always finds a format due to checks in setMedia()
2925
			$.each(this.formats, function(priority, format) {
2926
				if(self.html.support[format] && media[format]) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if self.html.support.format && media.format is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
2927
					self.status.src = media[format];
2928
					self.status.format[format] = true;
2929
					self.status.formatType = format;
2930
					return false;
2931
				}
2932
			});
2933
		},
2934
		_html_setAudio: function(media) {
2935
			this._html_setFormat(media);
2936
			this.htmlElement.media = this.htmlElement.audio;
2937
			this._html_initMedia(media);
2938
		},
2939
		_html_setVideo: function(media) {
2940
			this._html_setFormat(media);
2941
			if(this.status.nativeVideoControls) {
2942
				this.htmlElement.video.poster = this._validString(media.poster) ? media.poster : "";
2943
			}
2944
			this.htmlElement.media = this.htmlElement.video;
2945
			this._html_initMedia(media);
2946
		},
2947
		_html_resetMedia: function() {
2948
			if(this.htmlElement.media) {
2949
				if(this.htmlElement.media.id === this.internal.video.id && !this.status.nativeVideoControls) {
2950
					this.internal.video.jq.css({'width':'0px', 'height':'0px'});
2951
				}
2952
				this.htmlElement.media.pause();
2953
			}
2954
		},
2955
		_html_clearMedia: function() {
2956
			if(this.htmlElement.media) {
2957
				this.htmlElement.media.src = "about:blank";
2958
				// The following load() is only required for Firefox 3.6 (PowerMacs).
2959
				// Recent HTMl5 browsers only require the src change. Due to changes in W3C spec and load() effect.
2960
				this.htmlElement.media.load(); // Stops an old, "in progress" download from continuing the download. Triggers the loadstart, error and emptied events, due to the empty src. Also an abort event if a download was in progress.
2961
			}
2962
		},
2963
		_html_load: function() {
2964
			// This function remains to allow the early HTML5 browsers to work, such as Firefox 3.6
2965
			// A change in the W3C spec for the media.load() command means that this is no longer necessary.
2966
			// This command should be removed and actually causes minor undesirable effects on some browsers. Such as loading the whole file and not only the metadata.
2967
			if(this.status.waitForLoad) {
2968
				this.status.waitForLoad = false;
2969
				this.htmlElement.media.load();
2970
			}
2971
			clearTimeout(this.internal.htmlDlyCmdId);
2972
		},
2973
		_html_play: function(time) {
2974
			var self = this,
2975
				media = this.htmlElement.media;
2976
2977
			this.androidFix.pause = false; // Cancel the pause fix.
2978
2979
			this._html_load(); // Loads if required and clears any delayed commands.
2980
2981
			// Setup the Android Fix.
2982
			if(this.androidFix.setMedia) {
2983
				this.androidFix.play = true;
2984
				this.androidFix.time = time;
2985
2986
			} else if(!isNaN(time)) {
2987
2988
				// Attempt to play it, since iOS has been ignoring commands
2989
				if(this.internal.cmdsIgnored) {
2990
					media.play();
2991
				}
2992
2993
				try {
2994
					// !media.seekable is for old HTML5 browsers, like Firefox 3.6.
2995
					// Checking seekable.length is important for iOS6 to work with setMedia().play(time)
2996
					if(!media.seekable || typeof media.seekable === "object" && media.seekable.length > 0) {
2997
						media.currentTime = time;
2998
						media.play();
2999
					} else {
3000
						throw 1;
3001
					}
3002
				} catch(err) {
3003
					this.internal.htmlDlyCmdId = setTimeout(function() {
3004
						self.play(time);
3005
					}, 250);
3006
					return; // Cancel execution and wait for the delayed command.
3007
				}
3008
			} else {
3009
				media.play();
3010
			}
3011
			this._html_checkWaitForPlay();
3012
		},
3013
		_html_pause: function(time) {
3014
			var self = this,
3015
				media = this.htmlElement.media;
3016
3017
			this.androidFix.play = false; // Cancel the play fix.
3018
3019
			if(time > 0) { // We do not want the stop() command, which does pause(0), causing a load operation.
3020
				this._html_load(); // Loads if required and clears any delayed commands.
3021
			} else {
3022
				clearTimeout(this.internal.htmlDlyCmdId);
3023
			}
3024
3025
			// Order of these commands is important for Safari (Win) and IE9. Pause then change currentTime.
3026
			media.pause();
3027
3028
			// Setup the Android Fix.
3029
			if(this.androidFix.setMedia) {
3030
				this.androidFix.pause = true;
3031
				this.androidFix.time = time;
3032
3033
			} else if(!isNaN(time)) {
3034
				try {
3035
					if(!media.seekable || typeof media.seekable === "object" && media.seekable.length > 0) {
3036
						media.currentTime = time;
3037
					} else {
3038
						throw 1;
3039
					}
3040
				} catch(err) {
3041
					this.internal.htmlDlyCmdId = setTimeout(function() {
3042
						self.pause(time);
3043
					}, 250);
3044
					return; // Cancel execution and wait for the delayed command.
3045
				}
3046
			}
3047
			if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
3048
				this._html_checkWaitForPlay();
3049
			}
3050
		},
3051
		_html_playHead: function(percent) {
3052
			var self = this,
3053
				media = this.htmlElement.media;
3054
3055
			this._html_load(); // Loads if required and clears any delayed commands.
3056
3057
			// This playHead() method needs a refactor to apply the android fix.
3058
3059
			try {
3060
				if(typeof media.seekable === "object" && media.seekable.length > 0) {
3061
					media.currentTime = percent * media.seekable.end(media.seekable.length-1) / 100;
3062
				} else if(media.duration > 0 && !isNaN(media.duration)) {
3063
					media.currentTime = percent * media.duration / 100;
3064
				} else {
3065
					throw "e";
3066
				}
3067
			} catch(err) {
3068
				this.internal.htmlDlyCmdId = setTimeout(function() {
3069
					self.playHead(percent);
3070
				}, 250);
3071
				return; // Cancel execution and wait for the delayed command.
3072
			}
3073
			if(!this.status.waitForLoad) {
3074
				this._html_checkWaitForPlay();
3075
			}
3076
		},
3077
		_html_checkWaitForPlay: function() {
3078
			if(this.status.waitForPlay) {
3079
				this.status.waitForPlay = false;
3080
				if(this.css.jq.videoPlay.length) {
3081
					this.css.jq.videoPlay.hide();
3082
				}
3083
				if(this.status.video) {
3084
					this.internal.poster.jq.hide();
3085
					this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
3086
				}
3087
			}
3088
		},
3089
		_html_setProperty: function(property, value) {
3090
			if(this.html.audio.available) {
3091
				this.htmlElement.audio[property] = value;
3092
			}
3093
			if(this.html.video.available) {
3094
				this.htmlElement.video[property] = value;
3095
			}
3096
		},
3097
		_aurora_setAudio: function(media) {
3098
			var self = this;            
3099
			
3100
			// Always finds a format due to checks in setMedia()
3101
			$.each(this.formats, function(priority, format) {
3102
				if(self.aurora.support[format] && media[format]) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if self.aurora.support.format && media.format is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
3103
					self.status.src = media[format];
3104
					self.status.format[format] = true;
3105
					self.status.formatType = format;
3106
			
3107
					return false;
3108
				}
3109
			});
3110
			
3111
			this.aurora.player = new AV.Player.fromURL(this.status.src);
0 ignored issues
show
Bug introduced by
The variable AV seems to be never declared. If this is a global, consider adding a /** global: AV */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3112
			this._addAuroraEventListeners(this.aurora.player, this.aurora);
3113
3114
			if(this.options.preload === 'auto') {
3115
				this._aurora_load();
3116
				this.status.waitForLoad = false;
3117
			}
3118
		},
3119
		_aurora_resetMedia: function() {
3120
			if (this.aurora.player) {
3121
				this.aurora.player.stop();
3122
			}
3123
		},
3124
		_aurora_clearMedia: function() {
3125
			// Nothing to clear.
3126
		},
3127
		_aurora_load: function() {
3128
			if(this.status.waitForLoad) {
3129
				this.status.waitForLoad = false;
3130
				this.aurora.player.preload();
3131
			}
3132
		},
3133
		_aurora_play: function(time) {
3134
			if (!this.status.waitForLoad) {
3135
				if (!isNaN(time)) {
3136
					this.aurora.player.seek(time);
3137
				}
3138
			}
3139
			if (!this.aurora.player.playing) {
3140
				this.aurora.player.play();
3141
			}
3142
			this.status.waitForLoad = false;
3143
			this._aurora_checkWaitForPlay();
3144
			
3145
			// No event from the player, update UI now.
3146
			this._updateButtons(true);
3147
			this._trigger($.jPlayer.event.play);
3148
		},
3149
		_aurora_pause: function(time) {
3150
			if (!isNaN(time)) {
3151
				this.aurora.player.seek(time * 1000);
3152
			}
3153
			this.aurora.player.pause();
3154
			
3155
			if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
3156
				this._aurora_checkWaitForPlay();
3157
			}
3158
			
3159
			// No event from the player, update UI now.
3160
			this._updateButtons(false);
3161
			this._trigger($.jPlayer.event.pause);
3162
		},
3163
		_aurora_playHead: function(percent) {
3164
			if(this.aurora.player.duration > 0) {
3165
				// The seek() sould be in milliseconds, but the only codec that works with seek (aac.js) uses seconds.
3166
				this.aurora.player.seek(percent * this.aurora.player.duration / 100); // Using seconds
3167
			}
3168
				
3169
			if(!this.status.waitForLoad) {
3170
				this._aurora_checkWaitForPlay();
3171
			}
3172
		},
3173
		_aurora_checkWaitForPlay: function() {
3174
			if(this.status.waitForPlay) {
3175
				this.status.waitForPlay = false;
3176
			}
3177
		},
3178
		_aurora_volume: function(v) {
3179
			this.aurora.player.volume = v * 100;
3180
		},
3181
		_aurora_mute: function(m) {
3182
			if (m) {
3183
				this.aurora.properties.lastvolume = this.aurora.player.volume;
3184
				this.aurora.player.volume = 0;
3185
			} else {
3186
				this.aurora.player.volume = this.aurora.properties.lastvolume;
3187
			}
3188
			this.aurora.properties.muted = m;
3189
		},
3190
		_flash_setAudio: function(media) {
3191
			var self = this;
3192
			try {
3193
				// Always finds a format due to checks in setMedia()
3194
				$.each(this.formats, function(priority, format) {
3195
					if(self.flash.support[format] && media[format]) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if self.flash.support.format && media.format is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
3196
						switch (format) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3197
							case "m4a" :
3198
							case "fla" :
3199
								self._getMovie().fl_setAudio_m4a(media[format]);
3200
								break;
3201
							case "mp3" :
3202
								self._getMovie().fl_setAudio_mp3(media[format]);
3203
								break;
3204
							case "rtmpa":
3205
								self._getMovie().fl_setAudio_rtmp(media[format]);
3206
								break;
3207
						}
3208
						self.status.src = media[format];
3209
						self.status.format[format] = true;
3210
						self.status.formatType = format;
3211
						return false;
3212
					}
3213
				});
3214
3215
				if(this.options.preload === 'auto') {
3216
					this._flash_load();
3217
					this.status.waitForLoad = false;
3218
				}
3219
			} catch(err) { this._flashError(err); }
3220
		},
3221
		_flash_setVideo: function(media) {
3222
			var self = this;
3223
			try {
3224
				// Always finds a format due to checks in setMedia()
3225
				$.each(this.formats, function(priority, format) {
3226
					if(self.flash.support[format] && media[format]) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if self.flash.support.format && media.format is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
3227
						switch (format) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3228
							case "m4v" :
3229
							case "flv" :
3230
								self._getMovie().fl_setVideo_m4v(media[format]);
3231
								break;
3232
							case "rtmpv":
3233
								self._getMovie().fl_setVideo_rtmp(media[format]);
3234
								break;		
3235
						}
3236
						self.status.src = media[format];
3237
						self.status.format[format] = true;
3238
						self.status.formatType = format;
3239
						return false;
3240
					}
3241
				});
3242
3243
				if(this.options.preload === 'auto') {
3244
					this._flash_load();
3245
					this.status.waitForLoad = false;
3246
				}
3247
			} catch(err) { this._flashError(err); }
3248
		},
3249
		_flash_resetMedia: function() {
3250
			this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Must do via CSS as setting attr() to zero causes a jQuery error in IE.
3251
			this._flash_pause(NaN);
3252
		},
3253
		_flash_clearMedia: function() {
3254
			try {
3255
				this._getMovie().fl_clearMedia();
3256
			} catch(err) { this._flashError(err); }
3257
		},
3258
		_flash_load: function() {
3259
			try {
3260
				this._getMovie().fl_load();
3261
			} catch(err) { this._flashError(err); }
3262
			this.status.waitForLoad = false;
3263
		},
3264
		_flash_play: function(time) {
3265
			try {
3266
				this._getMovie().fl_play(time);
3267
			} catch(err) { this._flashError(err); }
3268
			this.status.waitForLoad = false;
3269
			this._flash_checkWaitForPlay();
3270
		},
3271
		_flash_pause: function(time) {
3272
			try {
3273
				this._getMovie().fl_pause(time);
3274
			} catch(err) { this._flashError(err); }
3275
			if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
3276
				this.status.waitForLoad = false;
3277
				this._flash_checkWaitForPlay();
3278
			}
3279
		},
3280
		_flash_playHead: function(p) {
3281
			try {
3282
				this._getMovie().fl_play_head(p);
3283
			} catch(err) { this._flashError(err); }
3284
			if(!this.status.waitForLoad) {
3285
				this._flash_checkWaitForPlay();
3286
			}
3287
		},
3288
		_flash_checkWaitForPlay: function() {
3289
			if(this.status.waitForPlay) {
3290
				this.status.waitForPlay = false;
3291
				if(this.css.jq.videoPlay.length) {
3292
					this.css.jq.videoPlay.hide();
3293
				}
3294
				if(this.status.video) {
3295
					this.internal.poster.jq.hide();
3296
					this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height});
3297
				}
3298
			}
3299
		},
3300
		_flash_volume: function(v) {
3301
			try {
3302
				this._getMovie().fl_volume(v);
3303
			} catch(err) { this._flashError(err); }
3304
		},
3305
		_flash_mute: function(m) {
3306
			try {
3307
				this._getMovie().fl_mute(m);
3308
			} catch(err) { this._flashError(err); }
3309
		},
3310
		_getMovie: function() {
3311
			return document[this.internal.flash.id];
3312
		},
3313
		_getFlashPluginVersion: function() {
3314
3315
			// _getFlashPluginVersion() code influenced by:
3316
			// - FlashReplace 1.01: http://code.google.com/p/flashreplace/
3317
			// - SWFObject 2.2: http://code.google.com/p/swfobject/
3318
3319
			var version = 0,
3320
				flash;
3321
			if(window.ActiveXObject) {
3322
				try {
3323
					flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
0 ignored issues
show
Bug introduced by
The variable ActiveXObject seems to be never declared. If this is a global, consider adding a /** global: ActiveXObject */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3324
					if (flash) { // flash will return null when ActiveX is disabled
3325
						var v = flash.GetVariable("$version");
3326
						if(v) {
3327
							v = v.split(" ")[1].split(",");
3328
							version = parseInt(v[0], 10) + "." + parseInt(v[1], 10);
3329
						}
3330
					}
3331
				} catch(e) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
3332
			}
3333
			else if(navigator.plugins && navigator.mimeTypes.length > 0) {
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3334
				flash = navigator.plugins["Shockwave Flash"];
3335
				if(flash) {
3336
					version = navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/, "$1");
3337
				}
3338
			}
3339
			return version * 1; // Converts to a number
3340
		},
3341
		_checkForFlash: function (version) {
3342
			var flashOk = false;
3343
			if(this._getFlashPluginVersion() >= version) {
3344
				flashOk = true;
3345
			}
3346
			return flashOk;
3347
		},
3348
		_validString: function(url) {
3349
			return (url && typeof url === "string"); // Empty strings return false
3350
		},
3351
		_limitValue: function(value, min, max) {
3352
			return (value < min) ? min : ((value > max) ? max : value);
3353
		},
3354
		_urlNotSetError: function(context) {
3355
			this._error( {
3356
				type: $.jPlayer.error.URL_NOT_SET,
3357
				context: context,
3358
				message: $.jPlayer.errorMsg.URL_NOT_SET,
3359
				hint: $.jPlayer.errorHint.URL_NOT_SET
3360
			});
3361
		},
3362
		_flashError: function(error) {
3363
			var errorType;
3364
			if(!this.internal.ready) {
3365
				errorType = "FLASH";
3366
			} else {
3367
				errorType = "FLASH_DISABLED";
3368
			}
3369
			this._error( {
3370
				type: $.jPlayer.error[errorType],
3371
				context: this.internal.flash.swf,
3372
				message: $.jPlayer.errorMsg[errorType] + error.message,
3373
				hint: $.jPlayer.errorHint[errorType]
3374
			});
3375
			// Allow the audio player to recover if display:none and then shown again, or with position:fixed on Firefox.
3376
			// This really only affects audio in a media player, as an audio player could easily move the jPlayer element away from such issues.
3377
			this.internal.flash.jq.css({'width':'1px', 'height':'1px'});
3378
		},
3379
		_error: function(error) {
3380
			this._trigger($.jPlayer.event.error, error);
3381
			if(this.options.errorAlerts) {
3382
				this._alert("Error!" + (error.message ? "\n" + error.message : "") + (error.hint ? "\n" + error.hint : "") + "\nContext: " + error.context);
3383
			}
3384
		},
3385
		_warning: function(warning) {
3386
			this._trigger($.jPlayer.event.warning, undefined, warning);
3387
			if(this.options.warningAlerts) {
3388
				this._alert("Warning!" + (warning.message ? "\n" + warning.message : "") + (warning.hint ? "\n" + warning.hint : "") + "\nContext: " + warning.context);
3389
			}
3390
		},
3391
		_alert: function(message) {
3392
			var msg = "jPlayer " + this.version.script + " : id='" + this.internal.self.id +"' : " + message;
3393
			if(!this.options.consoleAlerts) {
3394
				alert(msg);
3395
			} else if(window.console && window.console.log) {
3396
				window.console.log(msg);
3397
			}
3398
		},
3399
		_emulateHtmlBridge: function() {
3400
			var self = this;
3401
3402
			// Emulate methods on jPlayer's DOM element.
3403
			$.each( $.jPlayer.emulateMethods.split(/\s+/g), function(i, name) {
3404
				self.internal.domNode[name] = function(arg) {
3405
					self[name](arg);
3406
				};
3407
3408
			});
3409
3410
			// Bubble jPlayer events to its DOM element.
3411
			$.each($.jPlayer.event, function(eventName,eventType) {
3412
				var nativeEvent = true;
3413
				$.each( $.jPlayer.reservedEvent.split(/\s+/g), function(i, name) {
3414
					if(name === eventName) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if name === eventName is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
3415
						nativeEvent = false;
3416
						return false;
3417
					}
3418
				});
3419
				if(nativeEvent) {
3420
					self.element.bind(eventType + ".jPlayer.jPlayerHtml", function() { // With .jPlayer & .jPlayerHtml namespaces.
3421
						self._emulateHtmlUpdate();
3422
						var domEvent = document.createEvent("Event");
3423
						domEvent.initEvent(eventName, false, true);
3424
						self.internal.domNode.dispatchEvent(domEvent);
3425
					});
3426
				}
3427
				// The error event would require a special case
3428
			});
3429
3430
			// IE9 has a readyState property on all elements. The document should have it, but all (except media) elements inherit it in IE9. This conflicts with Popcorn, which polls the readyState.
3431
		},
3432
		_emulateHtmlUpdate: function() {
3433
			var self = this;
3434
3435
			$.each( $.jPlayer.emulateStatus.split(/\s+/g), function(i, name) {
3436
				self.internal.domNode[name] = self.status[name];
3437
			});
3438
			$.each( $.jPlayer.emulateOptions.split(/\s+/g), function(i, name) {
3439
				self.internal.domNode[name] = self.options[name];
3440
			});
3441
		},
3442
		_destroyHtmlBridge: function() {
3443
			var self = this;
3444
3445
			// Bridge event handlers are also removed by destroy() through .jPlayer namespace.
3446
			this.element.unbind(".jPlayerHtml"); // Remove all event handlers created by the jPlayer bridge. So you can change the emulateHtml option.
3447
3448
			// Remove the methods and properties
3449
			var emulated = $.jPlayer.emulateMethods + " " + $.jPlayer.emulateStatus + " " + $.jPlayer.emulateOptions;
3450
			$.each( emulated.split(/\s+/g), function(i, name) {
3451
				delete self.internal.domNode[name];
3452
			});
3453
		}
3454
	};
3455
3456
	$.jPlayer.error = {
3457
		FLASH: "e_flash",
3458
		FLASH_DISABLED: "e_flash_disabled",
3459
		NO_SOLUTION: "e_no_solution",
3460
		NO_SUPPORT: "e_no_support",
3461
		URL: "e_url",
3462
		URL_NOT_SET: "e_url_not_set",
3463
		VERSION: "e_version"
3464
	};
3465
3466
	$.jPlayer.errorMsg = {
3467
		FLASH: "jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ", // Used in: _flashError()
3468
		FLASH_DISABLED: "jPlayer's Flash fallback has been disabled by the browser due to the CSS rules you have used. Details: ", // Used in: _flashError()
3469
		NO_SOLUTION: "No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.", // Used in: _init()
3470
		NO_SUPPORT: "It is not possible to play any media format provided in setMedia() on this browser using your current options.", // Used in: setMedia()
3471
		URL: "Media URL could not be loaded.", // Used in: jPlayerFlashEvent() and _addHtmlEventListeners()
3472
		URL_NOT_SET: "Attempt to issue media playback commands, while no media url is set.", // Used in: load(), play(), pause(), stop() and playHead()
3473
		VERSION: "jPlayer " + $.jPlayer.prototype.version.script + " needs Jplayer.swf version " + $.jPlayer.prototype.version.needFlash + " but found " // Used in: jPlayerReady()
3474
	};
3475
3476
	$.jPlayer.errorHint = {
3477
		FLASH: "Check your swfPath option and that Jplayer.swf is there.",
3478
		FLASH_DISABLED: "Check that you have not display:none; the jPlayer entity or any ancestor.",
3479
		NO_SOLUTION: "Review the jPlayer options: support and supplied.",
3480
		NO_SUPPORT: "Video or audio formats defined in the supplied option are missing.",
3481
		URL: "Check media URL is valid.",
3482
		URL_NOT_SET: "Use setMedia() to set the media URL.",
3483
		VERSION: "Update jPlayer files."
3484
	};
3485
3486
	$.jPlayer.warning = {
3487
		CSS_SELECTOR_COUNT: "e_css_selector_count",
3488
		CSS_SELECTOR_METHOD: "e_css_selector_method",
3489
		CSS_SELECTOR_STRING: "e_css_selector_string",
3490
		OPTION_KEY: "e_option_key"
3491
	};
3492
3493
	$.jPlayer.warningMsg = {
3494
		CSS_SELECTOR_COUNT: "The number of css selectors found did not equal one: ",
3495
		CSS_SELECTOR_METHOD: "The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.",
3496
		CSS_SELECTOR_STRING: "The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.",
3497
		OPTION_KEY: "The option requested in jPlayer('option') is undefined."
3498
	};
3499
3500
	$.jPlayer.warningHint = {
3501
		CSS_SELECTOR_COUNT: "Check your css selector and the ancestor.",
3502
		CSS_SELECTOR_METHOD: "Check your method name.",
3503
		CSS_SELECTOR_STRING: "Check your css selector is a string.",
3504
		OPTION_KEY: "Check your option name."
3505
	};
3506
}));
3507